printf of VPS_SSH_KEY produced a corrupted private key on the runner
(libcrypto error). Switch to webfactory/ssh-agent which handles multiline
OpenSSH keys reliably.
Co-authored-by: Cursor <cursoragent@cursor.com>
Build the Docker image in GitHub Actions, publish to
ghcr.io/mauricioabh/arbpulse (latest + sha tags), then SSH into the
Hetzner VPS to docker compose pull + up -d with a health-check gate.
The VPS no longer builds images, keeping CPU/RAM free for the running
apps and making rollbacks a matter of pulling a previous sha tag.
- .github/workflows/vps-deploy.yml: build-push (GHCR) + deploy (SSH) jobs
- deploy/docker-compose.yml: app image now ghcr.io/mauricioabh/arbpulse
- deploy/deploy.sh: pulls from GHCR by default (BUILD=1 for local build),
default APP_DIR aligned to /root/projects/arbpulse
- docs: deploy/README.md CI/CD section + paths, README deploy section
Co-authored-by: Cursor <cursoragent@cursor.com>
Kraken WS v2 book channel does not send deletes for levels evicted from
its top-N window; without client-side truncation those levels lingered
forever as phantom quotes, eventually crossing the local book (bid >= ask)
and feeding the engine a fake permanent arbitrage (~$62.9M bogus P&L).
- BookSide.truncate() removes levels beyond the best depth prices from
the internal map (not just the emitted array)
- KrakenConnector uses depth 10 consistently (subscription + LocalBook)
and truncates both sides after every update
- ExchangeConnector.emit() drops internally crossed books, logs and
forces a resync (book reset + reconnect for a fresh snapshot)
- Unit tests for truncation and the crossed-book guard
- OpenSpec: order-book-integrity spec; change archived (2026-07-19)
Refs: Linear WAY-77
Co-authored-by: Cursor <cursoragent@cursor.com>
npm ci --prefix web installs the web package's file:.. dependency on root, which runs the root prepare script (husky). In the Docker build stages husky isn't installed, so 'husky' exits 127 and the build fails. 'husky || true' no-ops when the binary is absent (Docker/CI) while still running normally in local dev where husky is present.
Co-authored-by: Cursor <cursoragent@cursor.com>
The VPS already runs nginx+certbot on 80/443 for other apps, so bundled Caddy would collide. Make Caddy opt-in via a compose profile (WITH_CADDY=1); default deploy now runs only the app on 127.0.0.1:8080. Add an SSE-friendly nginx vhost (deploy/nginx/arbpulse.wayool.com.conf) and document the nginx+certbot integration path.
Co-authored-by: Cursor <cursoragent@cursor.com>
Set DOMAIN default to arbpulse.wayool.com and document the Cloudflare DNS setup (grey-cloud / DNS-only) so Caddy HTTP-01 and SSE work without proxy buffering.
Co-authored-by: Cursor <cursoragent@cursor.com>
Self-contained VPS deployment for 24/7 operation: app container behind Caddy with automatic HTTPS, idempotent deploy.sh, .env template, and runbook. SENTRY_TRACING defaults off to stay within the Sentry free-tier span quota.
Co-authored-by: Cursor <cursoragent@cursor.com>
Moves the completed change to openspec/changes/archive/ and creates the canonical openspec/specs/observability/spec.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
Spans are now created and exported to Sentry only when SENTRY_TRACING is enabled (default off), keeping 24/7 operation within the free-tier span quota. Error monitoring stays always-on. Includes OpenSpec change gate-sentry-spans (proposal, design, specs, tasks).
Co-authored-by: Cursor <cursoragent@cursor.com>
Capture REST/WS/SSE errors in Sentry, emit structured pino logs with correlation IDs, and trace the book-tick pipeline to Sentry via OpenTelemetry.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace hand-written OpenAPI and Swagger UI with schema-driven docs at /api-docs and Zod validation on request bodies.
Co-authored-by: Cursor <cursoragent@cursor.com>