Commit Graph

188 Commits

Author SHA1 Message Date
jgrusewski
671cb3d053 fix(ci): skip GPU-dependent tests when no nvidia RuntimeClass
49 ml tests (DQN, TFT, QAT, flash attention, ensemble adapters) fail
without a real GPU — CUDA stubs let the binary load but tensor ops
need libcuda. Skip these modules when nvidia-smi isn't available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:12:00 +01:00
jgrusewski
74944b1696 fix(ci): keep CUDA stubs when GPU not available
Without nvidia RuntimeClass, there's no real libcuda.so in the
container. The before_script was stripping CUDA stubs, leaving test
binaries (like backtesting) unable to load libcuda.so.1.

Now nvidia-smi is checked first: if GPU present, strip stubs (real
CUDA from RuntimeClass). If no GPU, keep stubs so CUDA-linked test
binaries can load. CUDA compute cap defaults to 89 (L4).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:16:25 +01:00
jgrusewski
5f2d7d670a fix(ci): make nvidia-smi optional for compile/test jobs
Compile and test jobs run on ci-compile (L4) without nvidia RuntimeClass
since they only need CUDA headers, not GPU access. The nvidia-smi call
was failing because the GPU device isn't passed through without the
RuntimeClass.

Now nvidia-smi failure is non-fatal for compile/test, with CUDA compute
cap defaulting to 89 (L4) for sccache partitioning. Training jobs still
require nvidia-smi to succeed (they need actual GPU access).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:02:28 +01:00
jgrusewski
e51ec73201 fix(ci): add optional: true to all needs references
When a commit doesn't touch source code (e.g. infra-only changes), the
changes: filters exclude build jobs from the pipeline. Without
optional: true, downstream jobs (train, deploy) fail with "needs X job
but X does not exist in the pipeline".

Now all needs entries use optional: true so pipelines succeed even when
upstream jobs are filtered out by changes: rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:41:09 +01:00
jgrusewski
46d686ee6e fix(ci): move nvidia RuntimeClass from runner default to per-job override
L4 ci-compile node was failing with 'no runtime for nvidia' because
fresh nodes take time to install nvidia drivers. Kaniko builds don't
need GPU at all. Now only Rust compile/test and training jobs request
nvidia RuntimeClass via KUBERNETES_RUNTIME_CLASS_NAME CI variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:07:35 +01:00
jgrusewski
914ecd6c89 fix(ci): ensure evaluate always runs after training, even on failure
Training and hyperopt jobs now capture exit codes and continue to
evaluation step regardless. Job still fails if training failed, but
eval output/artifacts are always available for debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:05:58 +01:00
jgrusewski
6e6cee733e perf(ci): remove no-op check stage, saves ~5 min pod startup
Check stage was just echoing "skipped" but still spun up an L4 pod.
Test and compile-services now start immediately (needs: []).
Infra-plan and drift-check moved from check→test stage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:58:01 +01:00
jgrusewski
610e0d446e perf(ci): parallelize compile+test, bump runner concurrency to 10
- compile-services now depends on check (not test), running in parallel
  with test stage — saves ~10 min from critical path
- Runner concurrent bumped 4→10 so all 9 Kaniko builds run simultaneously
- Runner default resources lowered (500m/1Gi) for lightweight Kaniko jobs;
  Rust compile/test/training override via KUBERNETES_*_REQUEST CI vars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:50:02 +01:00
jgrusewski
1a41f9475a refactor(infra): update all manifests for pool rename (always-on→services, ci-build→ci-compile/ci-training)
All K8s nodeSelectors, CI config, runner config, monitoring docs, and
smoke tests now reference the new pool names provisioned by terragrunt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:33:34 +01:00
jgrusewski
ce65e4ca42 feat(infra): add L4 compile pool alongside L40S training pool
Split GPU workloads across two pools:
- ci-compile (L4-1-24G): for cargo check/test/build — cheaper, same
  CUDA CC 8.9 as L40S, sufficient 24GB VRAM for compilation
- ci-build (L40S-1-48G): for hyperopt + training — 48GB VRAM needed
  for large model training batches

Runner defaults to ci-compile; training jobs override to ci-build
via KUBERNETES_NODE_SELECTOR. Both pools autoscale to zero when idle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:11:54 +01:00
jgrusewski
ef6c77c036 perf(ci): give compile jobs all 8 CPU cores on L40S node
Use KUBERNETES_CPU_REQUEST/LIMIT CI variables to differentiate:
- Compile jobs (.rust-base): 7000m/7800m — CPU-bound, benefits from
  all cores for parallel Rust compilation + linking
- Training jobs (.train-validate-base): 2000m/3500m — GPU-bound,
  low CPU allows 2 concurrent training jobs on same node

Previously all jobs shared 3500m/7000m defaults, wasting half the
L40S node's CPU during compilation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:07:23 +01:00
jgrusewski
74f47623ca fix(ci): create ld.mold wrapper (not mold) for clang -fuse-ld=mold
clang's -fuse-ld=mold searches for "ld.mold" binary, not "mold".
Previous wrapper created /usr/local/bin/mold which clang never finds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 08:04:27 +01:00
jgrusewski
7954495bb3 fix(ci): fix mold→lld fallback wrapper for argv[0] check
lld checks argv[0] to determine its mode (ld.lld, ld64.lld, etc).
A symlink named ld.mold pointing to ld.lld still invokes with
argv[0]="ld.mold" which lld rejects as "generic driver".

Replace symlink with a wrapper script that explicitly invokes ld.lld,
so clang -fuse-ld=mold finds /usr/local/bin/mold and it delegates
correctly to the ELF linker.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 02:05:29 +01:00
jgrusewski
7546b54224 feat(ci): plan-on-push + manual-apply for infra pipeline
- infra-plan: now triggers on push to main (was MR-only)
- infra-apply: now manual trigger (was auto on push to main)
- infra-apply depends on infra-plan (must plan before apply)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:37:30 +01:00
jgrusewski
5198d42f6b fix(ci): add mold→lld fallback for CI builder transition
The .cargo/config.toml now uses -fuse-ld=mold, but the CI builder image
hasn't been rebuilt yet with mold. Add a symlink fallback in .rust-base
before_script: if mold isn't found, symlink ld.mold → ld.lld so builds
continue working until the builder image is rebuilt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:08:23 +01:00
jgrusewski
f13b0df6e8 feat(infra): upgrade CI to L40S + mold linker for faster builds
- Switch linker from lld to mold (~2-5x faster linking for large binaries)
  - Install mold 2.35.1 in CI builder Dockerfile
  - Update .cargo/config.toml: -fuse-ld=mold
- Upgrade CI build pool: L4-1-24G → L40S-1-48G (~2x training throughput)
  - Increase max_size from 1 to 2 (allows concurrent jobs, fixes scheduling deadlocks)
  - Update runner resource limits for L40S node (24 vCPU, 96GB)
- Update runner-values.yaml comments and .gitlab-ci.yml header

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 00:05:23 +01:00
jgrusewski
e01952c5d7 feat(ci): add dev-release profile for fast CI iteration
Add Cargo profile `dev-release` (opt-level=2, thin LTO, 16 codegen-units)
for ~3-5x faster compile vs full release. Activate by setting DEV_RELEASE=true
in pipeline variables — skips check stage and uses fast profile.

- Move profile definitions from .cargo/config.toml to Cargo.toml (config.toml
  silently ignores [profile.*] blocks — they were dead code)
- Add hft and bench profiles to Cargo.toml (were only in config.toml)
- compile-services now selects profile via $DEV_RELEASE env var
- test stage uses optional check dependency (runs without check in dev mode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:53:07 +01:00
jgrusewski
b09ebfc3cb feat(ml): add HyperparameterOptimizable trainers for all 8 supervised models
Extend hyperopt infrastructure to support all 10 ML models (DQN, PPO +
8 supervised). Previously only TFT and Mamba2 had hyperopt trainers.

- Add HyperparameterOptimizable impl for Liquid, TGGN, TLOB, KAN, xLSTM, Diffusion
- Create shared_data.rs with common data prep utilities (build_flat_pairs,
  build_sequence_pairs, write_trial_result_json)
- Extend hyperopt_baseline_supervised binary to dispatch all 8 models
  (individual, "both" for tft+mamba2, "all" for all 8)
- Add CI jobs: 7 train-validate + 10 hyperopt jobs for all models
- Fix DiffusionMetrics NaN default, XLSTMMetrics serde, safe indexing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:47:52 +01:00
jgrusewski
1fe2d4117b ci: add dedicated PPO hyperopt training job
Adds hyperopt-ppo job (manual, 4h timeout) that runs:
1. PSO hyperopt (20 trials, 15 epochs each) to find optimal PPO params
2. Full training with best params
3. Walk-forward evaluation with Sharpe/MaxDD/WinRate metrics

Artifacts: ppo_hyperopt_results.json + ppo_eval_report.json (90 days)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:10:26 +01:00
jgrusewski
0c1fe12645 feat(ml): add evaluate_supervised binary + PPO eval in CI
New evaluate_supervised binary runs walk-forward inference on supervised
model checkpoints (TFT, Mamba2, etc.), converts directional predictions
to trading signals, and computes Sharpe/MaxDD/WinRate/DirAccuracy.

CI changes:
- train-validate-dqn → train-validate-rl (trains+evals DQN+PPO)
- train-validate-tft now runs evaluate_supervised after training
- web/api fallback rules added to train-validate and deploy stages
- evaluate_supervised added to compile-services and Docker images

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:31:45 +01:00
jgrusewski
fc4f55999b ci: add web/api fallback rules for forced pipeline runs
When changes: glob evaluation fails (known GitLab CE bug) or when only
CI config is modified, web/API-triggered pipelines now always run all
code stages unconditionally.  This also serves as the manual override
for pipeline #110 which silently dropped all jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:54:35 +01:00
jgrusewski
f21b58625e ci: add DQN evaluation step and skip builds on CI-only changes
Add evaluate_baseline after DQN training smoke test so we get Sharpe,
MaxDD, WinRate, and ProfitFactor in the pipeline artifacts. Remove
.gitlab-ci.yml from changes: filters so CI-config-only pushes no longer
trigger the full check→test→compile→build pipeline (~20 min saved).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:42:56 +01:00
jgrusewski
9e8e36c883 fix(ci): use workspace dir for training output (permission denied on /output)
CI runner pods don't have write access to root filesystem.
Use ${CI_PROJECT_DIR}/output instead of /output for training artifacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:45:20 +01:00
jgrusewski
a6b49b909b revert: keep runner on L4 ci-build pool (CUDA 8.9)
H100 is sm_90, not compatible with existing sm_89 sccache.
Revert runner node selector and resource limits to ci-build (L4).
Training validation stage (manual DQN/TFT smoke tests) stays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:02:25 +01:00
jgrusewski
df4ef104b7 ci: move runner to H100 pool, add training validation stage
- Runner node selector: ci-build (L4) → gpu-training (H100) for faster
  compilation (2x+ vCPUs) and native GPU training support
- Resource limits bumped: 20 vCPU / 128Gi (was 10 vCPU / 38Gi)
- New 'train' stage with manual DQN and TFT validation jobs
  (50-step smoke tests to verify CUDA + model correctness)
- Requires helm upgrade of gitlab-runner with new values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:56:22 +01:00
jgrusewski
a414436ae2 fix(ci): add workflow:rules to prevent empty pipeline creation
GitLab CE silently drops push pipelines when changes: path globs
fail to match, creating 0-job pipelines that instantly fail.
Adding explicit workflow:rules ensures the pipeline is always
created; individual job rules still handle filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 18:10:44 +01:00
jgrusewski
cc8abfef24 ci: trigger pipeline for build speed validation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 17:49:39 +01:00
jgrusewski
4a202207d3 ci: trigger rebuild for TFT sequence_length fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:51:18 +01:00
jgrusewski
f565a039b6 ci: trigger rebuild for TFT zero-dim fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:02:14 +01:00
jgrusewski
9bf2a52cbb ci: update header comment to reflect mixed GPU pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:42:02 +01:00
jgrusewski
73b368a0de fix(ci): detect GPU at runtime, partition sccache by compute cap
The CI runner pool has both L4 (sm_89) and H100 (sm_90) nodes.
Hardcoding CUDA_COMPUTE_CAP causes PTX mismatches when sccache
serves objects compiled for the wrong architecture.

- Detect compute capability via nvidia-smi at job start
- Partition sccache into /mnt/sccache/sm_89 and sm_90
- Each GPU type maintains its own warm cache

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:04:52 +01:00
jgrusewski
64a4f4fc0d fix(ci): purge sccache before test — stale L4 PTX fails on H100
sccache PVC holds CUDA kernel objects compiled for sm_89 (L4).
After moving the runner pool to H100 (sm_90), these produce
CUDA_ERROR_INVALID_PTX at runtime. Nuke the cache so candle
recompiles kernels for the correct compute capability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:59:03 +01:00
jgrusewski
0f9d756caa feat: on-demand training dispatch via K8s Jobs with sidecar uploader
Extend ml_training_service to dispatch GPU training jobs as K8s batch/v1
Jobs, collect results via a Rust sidecar uploader, and support model
promotion with operator approval via fxt CLI.

- K8s dispatcher creates Jobs on gpu-training pool with native sidecar
- training_uploader crate: watches DONE/FAILED marker, uploads to S3,
  reports completion via ReportJobCompletion gRPC
- PromotionManager compares metrics, queues better models for approval
- 4 new proto RPCs: ReportJobCompletion, ListPendingPromotions,
  ApprovePromotion, RejectPromotion
- fxt commands: train start, model list/approve/reject
- Training binaries write DONE/FAILED markers + metrics.json
- Dockerfile, K8s job template, and CI pipeline updated
- StartTraining gracefully falls back to in-process when outside K8s
- 27 new tests (16 service + 11 promotion), 141 total service tests pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:43:17 +01:00
jgrusewski
5853a704ce fix(ci): update CUDA_COMPUTE_CAP to 90 for H100 gpu-training pool
The CI runner now runs on H100 (compute cap 9.0), not L4 (8.9).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:55:55 +01:00
jgrusewski
6a24c3d9c6 fix(ci): map deploy image names to actual K8s deployment names
Deploy was using underscore names (trading_service) but K8s deployments
use hyphens (trading-service), causing 7/8 services to silently fail.
Uses explicit image_repo:deployment:container mapping table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:25:56 +01:00
jgrusewski
d1657871d3 fix(ci): rewrite kubeconfig to in-cluster API endpoint for deploy
The deploy pod runs inside Kapsule but the kubeconfig points to the
external API URL (api.k8s.fr-par.scw.cloud:6443). Due to pod CIDR
overlap with the egress path, the connection is reset by peer. Sed
rewrites the server URL to kubernetes.default.svc (in-cluster endpoint)
while keeping the scw exec plugin for token auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:19:16 +01:00
jgrusewski
013740f8a9 fix(ci): export SCW credentials for deploy kubeconfig exec plugin
The scw CLI used by the kubeconfig exec plugin (get-token) needs
SCW_ACCESS_KEY, SCW_SECRET_KEY, SCW_DEFAULT_PROJECT_ID, and
SCW_DEFAULT_ORGANIZATION_ID environment variables. Falls back to
project ID for org ID (common for single-org Scaleway accounts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:38:44 +01:00
jgrusewski
e3b8fe9382 fix(ci): deploy job uses infra-runner with scw + kubectl
Deploy was silently failing — bitnami/kubectl image lacks scw CLI
needed by Kapsule kubeconfig credential plugin. Now uses infra-runner
(has scw), installs kubectl inline until image is rebuilt. Adds
cluster-info check before deploy and proper error reporting per service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:50:53 +01:00
jgrusewski
f0bbca23a5 perf(ci): compile training binaries with CUDA in compile-services job
Training image was recompiling from scratch inside Kaniko (~16+ min)
without sccache. Now training binaries are built in compile-services
with --features ml/cuda and PVC sccache (warm cache from service
binaries), then packaged into a CUDA runtime image (~30s).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 01:37:52 +01:00
jgrusewski
c5db5aa39e perf(ci): compile once with PVC sccache, package with Kaniko
Split the build pipeline: one compile-services job builds all 8 service
binaries with PVC-backed sccache, saves as artifacts. Then 9 Kaniko jobs
just package pre-built binaries into slim runtime images (~30s each).

Before: 9 parallel Kaniko jobs each doing full cargo build --release
  (~20min each, no sccache, 9x duplicated dep compilation)
After:  1 compile job with sccache (~5min cached) + 9 package jobs (~30s)

- Add compile stage between test and build
- Add Dockerfile.runtime (minimal debian + pre-built binary)
- Add Dockerfile.web-gateway-runtime (Node dashboard + pre-built binary)
- Keep Dockerfile.training via Kaniko (needs CUDA dev image for H100)
- Remove all SCCACHE_BUCKET build-args from service builds
- Use dir:// context for Kaniko (only sends build-out/ dir, not full repo)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:50:25 +01:00
jgrusewski
754baeb434 perf(ci): skip check+clippy stage — test already compiles workspace
The check stage ran cargo check + clippy (~6min) before tests, but
the test stage compiles the same workspace anyway. Skip check with
an echo pass-through to save ~6min per pipeline. Easy to uncomment
when clippy enforcement is needed (e.g., before releases).

Also adds sccache stats to the test job for cache monitoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:24:57 +01:00
jgrusewski
c67ae083a9 fix(ci): remove stale SCCACHE_BUCKET override — S3 CI vars deleted
The SCCACHE_BUCKET, SCCACHE_REGION, and SCCACHE_ENDPOINT CI variables
were deleted from GitLab settings. The .rust-base override is no longer
needed — sccache now uses SCCACHE_DIR (PVC) by default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:14:09 +01:00
jgrusewski
ff8a275d47 fix(ml): widen flaky QAT checkpoint test range + use PVC sccache
- Widen observer checkpoint test bounds from 4σ to 5σ — random
  calibration data can exceed 4.0 with 100 batches of normal(0,1)
- Override SCCACHE_BUCKET="" in .rust-base so check/test jobs use
  PVC-backed SCCACHE_DIR instead of S3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:55:35 +01:00
jgrusewski
7b9da53603 infra(ci): switch CI builds from H100 to L4 — 4.7x cost reduction
Create dedicated ci-build node pool (L4-1-24G, €0.75/hr) replacing
H100 (€3.50+/hr) for CI builds. H100 reserved for training only.

- Add ci-build pool to Terraform (L4-1-24G, scale-to-zero, fr-par-2)
- Update GitLab Runner to target ci-build pool with L4-sized limits
- Change CUDA_COMPUTE_CAP from 90 (H100) to 89 (L4) in CI
- Dockerfile.training keeps CUDA_COMPUTE_CAP=90 for H100 training

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:30:04 +01:00
jgrusewski
267240530d perf(ci): enable Kaniko layer caching + Docker Hub auth on all builds
- Add --cache=true --cache-repo to all 12 Kaniko builds
- Cache Docker layers in Scaleway CR (rg.fr-par.scw.cloud/foxhunt-ci/cache)
- Add Docker Hub auth to devcontainer + infra-runner prepare jobs
- First build populates cache; subsequent builds skip base image pulls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:20:44 +01:00
jgrusewski
373a6f33a1 fix(ci): add Docker Hub auth to Kaniko to avoid pull rate limits
All Kaniko builds hit Docker Hub anonymous rate limit (100 pulls/6h).
Add DOCKERHUB_USERNAME + DOCKERHUB_TOKEN to config.json alongside
Scaleway CR credentials.

Requires CI variables: DOCKERHUB_USERNAME, DOCKERHUB_TOKEN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:15:40 +01:00
jgrusewski
51460a3382 perf(ci): switch sccache from S3 to local block storage PVC
- Create 20Gi sccache-pvc (scw-bssd) for fast local cache hits
- Mount at /mnt/sccache in CI build pods via runner helm values
- Use SCCACHE_DIR instead of SCCACHE_BUCKET for check/test jobs
- Kaniko builds keep S3 sccache (can't mount PVCs in Kaniko)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:12:34 +01:00
jgrusewski
ac688cac24 fix(ci): skip Rust builds on infra-only changes, remove stale files
Add `rules:` with `changes:` filters to check, test, and .kaniko-base
jobs so the Rust build pipeline only triggers when source code changes
(crates/, bin/, services/, Cargo.*). Prevents H100 spin-up on
infra-only pushes.

Remove 31 stale/orphan files (-11,885 lines):
- monitoring/ directory (duplicated by config/grafana + config/prometheus)
- 10 broken/placeholder migration files (.broken, .skip)
- 10 unreferenced config files (haproxy, nginx-lb, mutants, etc.)

Add 3 historical design docs from previous restructure work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:45:44 +01:00
jgrusewski
980489edc5 fix(ci): use relative artifact paths and avoid PIPESTATUS in drift check
- Artifact paths changed from /tmp/ to ${CI_PROJECT_DIR}/ for GitLab
  k8s executor compatibility
- Drift check uses $? instead of PIPESTATUS (Alpine sh doesn't support
  bash arrays)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:51:46 +01:00
jgrusewski
1caeb0b0d6 ci: add IaC pipeline (plan on MR, apply on merge, weekly drift check)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:48:57 +01:00