# Refresh the LIVE cockpit paper book (TRUSTED 2-edge nav + ALL tracked sleeve returns) over warehouse
# history, as an isolated one-shot Job.  `fxhnt paper-backfill --days 1650 --costs` (NET of cost + funding).
#
# DURABLE BATCH PATTERN (post warehouse->TimescaleDB consolidation): git-sync the latest src (so the new
# factory + multi-track code runs), read the warehouse over the NETWORK from TimescaleDB (FXHNT_FEATURE_STORE=
# postgres) instead of the local DuckDB file, and give the Job its OWN memory budget (4Gi) — separate from the
# 2Gi dagster daemon that OOM'd when batch ran inside it. Idempotent per run_date -> safe to re-run.
#
# WHY still podAffinity to dagster + the PVC: the warehouse READS are now networked (Timescale), but the
# worst_basis Parquet side-store + the surfer data dir still live on the RWO `fxhnt-surfer-data` PVC, so the
# Job co-locates with dagster to mount it. (Moving worst_basis off the PVC -> a fully node-agnostic batch pool
# is the documented next step; the own-memory Job already ends the daemon OOM.)
apiVersion: batch/v1
kind: Job
metadata:
  name: fxhnt-paper-backfill
  namespace: foxhunt
  labels: { app.kubernetes.io/name: fxhnt-paper-backfill, app.kubernetes.io/part-of: foxhunt }
spec:
  backoffLimit: 1
  ttlSecondsAfterFinished: 604800   # 7d
  template:
    metadata:
      labels: { app.kubernetes.io/name: fxhnt-paper-backfill, app.kubernetes.io/part-of: foxhunt }
    spec:
      restartPolicy: Never
      imagePullSecrets:
        - name: scw-registry
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector: { matchLabels: { app.kubernetes.io/name: dagster } }
              topologyKey: kubernetes.io/hostname   # co-locate with dagster for the RWO surfer-data PVC (worst_basis side-store)
      initContainers:
        - name: git-sync                            # clone master src -> /code so `fxhnt` runs the NEW code (factory + multi-track)
          image: alpine/git:latest
          command: [/bin/sh, -c]
          args:
            - |
              mkdir -p /root/.ssh && cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519 && chmod 600 /root/.ssh/id_ed25519
              printf 'Host *\n  StrictHostKeyChecking no\n  UserKnownHostsFile /dev/null\n' > /root/.ssh/config
              rm -rf /code/src
              git clone --depth 1 --branch master --filter=blob:none --sparse \
                "ssh://git@gitea-ssh.gitea.svc.cluster.local:22/gitadmin/fxhnt.git" /tmp/repo
              cd /tmp/repo && git sparse-checkout set src && [ -d /tmp/repo/src ]
              cp -a /tmp/repo/src /code/src && echo "git-sync OK: $(git rev-parse --short HEAD)"
          resources: { requests: { cpu: 50m, memory: 64Mi }, limits: { cpu: 500m, memory: 256Mi } }
          volumeMounts:
            - { name: code, mountPath: /code }
            - { name: git-ssh-key, mountPath: /etc/git-ssh, readOnly: true }
      containers:
        - name: backfill
          image: rg.fr-par.scw.cloud/bizworx/fxhnt-cockpit:latest
          command: ["fxhnt"]
          args: ["paper-backfill", "--days", "1650", "--costs"]
          env:
            - { name: PYTHONPATH, value: /code/src }                  # git-sync'd new code wins over the baked image
            - { name: FXHNT_FEATURE_STORE, value: "postgres" }        # warehouse reads -> TimescaleDB (networked)
            - { name: FXHNT_WAREHOUSE_PATH, value: /data/surfer/warehouse.duckdb }   # legacy DuckDB (rollback if flag unset)
            - { name: FXHNT_SURFER_DATA_DIR, value: /data/surfer }     # worst_basis Parquet side-store lives here
            - { name: FXHNT_OPERATIONAL_DSN, value: "postgresql+psycopg://foxhunt@postgres.foxhunt.svc.cluster.local:5432/fxhnt" }
            - name: PGPASSWORD
              valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
            - { name: PYTHONUNBUFFERED, value: "1" }
          resources:
            requests: { memory: "1Gi", cpu: "500m" }
            limits: { memory: "4Gi", cpu: "2" }      # OWN budget (separate from the 2Gi daemon that OOM'd)
          volumeMounts:
            - { name: surfer-data, mountPath: /data }
            - { name: code, mountPath: /code, readOnly: true }
      volumes:
        - { name: surfer-data, persistentVolumeClaim: { claimName: fxhnt-surfer-data } }
        - { name: code, emptyDir: {} }
        - { name: git-ssh-key, secret: { secretName: argo-git-ssh-key, defaultMode: 256 } }
---
# Egress: default-deny-all -> DNS + Postgres (5432, warehouse+operational) + external 443 (sleeve fetches:
# unlock->DefiLlama, prices) + gitea-sshd (2222, git-sync).
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: fxhnt-paper-backfill
  namespace: foxhunt
  labels: { app.kubernetes.io/part-of: foxhunt }
spec:
  podSelector: { matchLabels: { app.kubernetes.io/name: fxhnt-paper-backfill } }
  policyTypes: [Egress]
  egress:
    - ports: [{ port: 53, protocol: UDP }, { port: 53, protocol: TCP }]
    - to: [{ podSelector: { matchLabels: { app.kubernetes.io/name: postgres } } }]
      ports: [{ port: 5432, protocol: TCP }]
    - to: [{ namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: gitea } }, podSelector: { matchLabels: { app.kubernetes.io/name: gitea } } }]
      ports: [{ port: 2222, protocol: TCP }, { port: 22, protocol: TCP }]
    - to: [{ ipBlock: { cidr: 0.0.0.0/0, except: [10.32.0.0/16, 172.16.0.0/16] } }]   # external HTTPS for sleeve fetches
      ports: [{ port: 443, protocol: TCP }]
