Hetzner Python Gate
Date: 2026-05-05
Objective
Turn the remaining Python blocker into a repeatable server-side gate for the Hetzner rebuild.
This gate focuses only on the two Python services:
- Zweistein Query Engine
- Zweistein Ingestion Worker
It does not replace the full stack runbook. It gives the riskiest Python/Torch part its own early proof before the remaining application images are built.
What Was Added
scripts/hetzner-python-gate.mjsServer-guarded helper for Python preflight, Torch wheel probe, Query Engine build, Ingestion Worker build, import probes, Python subset startup, Compose inspection, and Query Engine health.package.jsonscripts:hetzner:python:planhetzner:python:commandshetzner:python:preflighthetzner:python:torchhetzner:python:build:queryhetzner:python:build:ingestionhetzner:python:buildhetzner:python:importshetzner:python:uphetzner:python:pshetzner:python:health
Safety Rules
- Heavy commands require native Linux x64/amd64.
- The helper requires at least 40 GiB free disk unless
HETZNER_PYTHON_GATE_ALLOW_LOW_DISK=1is set intentionally. - Runtime commands require real ignored Hetzner env files:
configs/hetzner/frontend-build.envconfigs/hetzner/zweistein-query-engine.envconfigs/hetzner/zweistein-ingestion-worker.env
- The helper does not print env values, logs, tokens, or database rows.
- The local Mac can print the plan and command lines, but it is expected to fail
hetzner:python:preflight.
Server Workflow
Run this on the Hetzner host after source sync, npm install, and real runtime config:
npm run hetzner:python:plan
npm run hetzner:python:commands
Then run the server gate:
npm run hetzner:python:preflight
npm run hetzner:env:check
npm run hetzner:python:torch
npm run hetzner:python:build:query
npm run hetzner:python:build:ingestion
npm run hetzner:python:imports
npm run hetzner:python:up
npm run hetzner:python:ps
npm run hetzner:python:health
If this passes, continue the full platform stack:
npm run hetzner:stack:build
npm run hetzner:stack:up
npm run hetzner:health:check
npm run hetzner:evidence:collect
Exact Command Shape
The helper prints these server commands through npm run hetzner:python:commands:
docker run --rm --platform linux/amd64 python:3.11-slim python -m pip install --dry-run --index-url https://download.pytorch.org/whl/cpu 'torch==2.10.0+cpu'
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml build query-engine
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml build ingestion-worker
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml run --rm --no-deps --entrypoint python query-engine -c "import main; print('query main import ok')"
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml run --rm --no-deps --entrypoint python ingestion-worker -c "import redis_worker; import message_processor; print('ingestion imports ok')"
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml up -d redis query-engine ingestion-worker
docker compose --env-file configs/hetzner/frontend-build.env -f docker-compose.hetzner.yml ps --format json redis query-engine ingestion-worker
curl -fsS http://127.0.0.1:5001/healthz
Running-State Gate
npm run hetzner:python:ps is a real gate, not just a display command.
It runs Docker Compose with JSON output, parses the returned service rows, and fails unless all three Python-subset services are present and running:
redisquery-engineingestion-worker
This is especially important for ingestion-worker, because it is a worker process rather than an HTTP service with its own health endpoint.
Local Verification Evidence
node --check scripts/hetzner-python-gate.mjspassed.npm run hetzner:python:planprints the ordered Python server gate.npm run hetzner:python:commandsprints exact Docker and Docker Compose commands.npm run hetzner:python:commandsnow showsps --format json redis query-engine ingestion-worker.npm run hetzner:python:psfails locally as expected before any server state is inspected, because the command is guarded for native Linux x64/amd64.npm run hetzner:python:preflightfails locally as expected:- platform is
darwin arm64; - Docker Compose is missing in the local Docker CLI;
- free disk is about 7.6 GiB;
- minimum Python gate disk is 40 GiB;
- the helper is guarded for native Linux x64/amd64.
- platform is
Current Boundary
This is still not Python runtime proof.
The actual gate must pass on the Hetzner/Linux host before the full port can be considered complete.