3 Commits

Author SHA1 Message Date
herzogflorian
c057f8efb7 Kubernetes deployment: shared data directory, write lock, probes
A third deployment next to the two on the DGX Spark, which stay as they
are: deploy/k8s/ has its own image and Kustomize manifests. The API is a
Deployment with probes, the data a PersistentVolumeClaim, the nightly
update a CronJob; overlays/gpu adds cuOpt on a GPU of the cluster.

Five assumptions of the single-container setup did not hold for pods, so
the service changed (on the Spark nothing changes that one would notice):

- probes: GET /health/live (async, no I/O) and GET /health/ready (data
  directory readable); neither needs cuOpt or market data, so a cuOpt
  outage never gets the API restarted. /health is unchanged
- DataStore replaces every file atomically (temporary file renamed into
  place) and saves the manifest last; the API reloads its market data
  when the manifest changes, so it serves what a CronJob wrote
- one writer at a time across processes and pods: an flock on
  /data/.write.lock, taken by API jobs and the CLI's data commands
  (setup, reselect, update, clean, snapshot); a second writer gets 409 or
  exit status 3, with the holder's name. `clean` now updates the manifest
- job records live in /data/jobs/ and are written at every status
  change: every replica answers GET /jobs/{id}, and a job whose process
  has gone is reported failed ("interrupted")
- the image runs as uid 10001 under a read-only root file system, with
  the library versions pinned to deploy/apptainer/constraints.txt (SciPy
  1.18 releases the GIL while HiGHS solves, so the liveness probe is
  answered during an optimisation)

docs/KUBERNETES.md is the guide (build, deploy, load the data, operate,
troubleshooting); README, USAGE and ARCHITECTURE point to it.

Both kustomizations render (kubectl kustomize); the k3s test of the
deployment is recorded in docs/KUBERNETES.md. 149 tests (148 pass, the
cuOpt round trip skipped without a server).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 07:27:43 +01:00
herzogflorian
772aa2de84 Setup: exact candidate symbols and a quiet run on students' Sparks
On a student Spark the installer's data step printed hundreds of red
yfinance "Quote not found for symbol" lines and built a universe of 652
instead of ~745 stocks. Cause: the iShares holdings download (German site)
answers 404 since October 2026, and setup fell back to Wikipedia's STOXX
600 table, whose Reuters-style codes give Yahoo symbols that do not exist
(BNPP.PA for BNP.PA, NOV-N.SW for NOVN.SW, VESTAS.CO for VWS.CO).

- sources: the iShares file is read from the Swiss site (same German CSV,
  same parser), the German address stays as a spare; when iShares fails,
  setup uses the snapshot shipped in quantcore/data/static and not the
  Wikipedia guesses (now a last resort when no snapshot ships); only a
  primary source refreshes the snapshot
- yahoo: yfinance's per-symbol ERROR lines are silenced during the
  metadata step and summarised in one line
- install.sh: builds the data with `qc setup --offline`, so every student
  gets the universe of the shipped lists (the course data set's); new
  --rebuild-data moves the existing data aside and builds it anew
- qc.sh: the image build attempt logs to ~/quantcore/build.log; a Spark
  that allows no build shows one plain line, then the no-build setup
- tests for the source order, the address fallback and the summary

Tested on a stripped-down machine (no git/curl/wget/python3, broken
APPTAINER_TMPDIR): install, then install.sh --rebuild-data built 746
stocks (382 US, 364 Europe) from the 1117 shipped candidates in under
10 minutes with no yfinance error line; self-test passes; qc upgrade
rebuilt and restarted. 142 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:03:20 +02:00
herzogflorian
3cd3854b2f Add the quantcore.data package; anchor .gitignore rules to the root
The unanchored `data/` rule, meant for the market-data directory, also
matched the Python subpackage quantcore/data/, so a fresh clone could not
import quantcore.data. `/data/`, `/build/` and `/dist/` now match only at
the repository root.

qc.sh: the virtualenv install stops when the installed package does not
start, and the self-test runs from / so that it imports the installed
package rather than the sources in the working directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:00:25 +02:00