Commit Graph

1535 Commits

Author SHA1 Message Date
jgrusewski
2fbb19d9df refactor(ml): rename real_data_loader to data_loader
The real_ prefix was misleading — there is no fake data loader.
Mechanical rename across 18 source files, no logic changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
3d679e824f feat(ml): GPU saturation final — DQN PER deferral, PPO trajectory batching, Liquid/TGGN sync reduction, DoubleBuffer wiring
- DQN PER: defer td_errors to_vec1() after loss.to_scalar() — piggyback on
  existing pipeline flush instead of forcing premature GPU→CPU stall
- PPO trajectories: capacity-hint Vec allocations, extend_flat_states methods,
  states_flat field on TrajectoryBatch for zero-copy GPU upload
- TGGN validate(): batch N per-sample losses on GPU → single to_scalar() sync
  (was N GPU→CPU syncs)
- Liquid backward(): batch grad-norm per-param sqr().sum_all() on GPU → single
  to_scalar() sync (was N GPU→CPU syncs per optimizer step)
- Liquid validate(): same N→1 GPU sync reduction as TGGN
- DQN trainer: restore EpochPrefetcher/DoubleBufferedLoader API (wrongly deleted)
- train_baseline_rl: wire DoubleBuffer GPU pre-upload — after CPU prefetch
  completes, immediately upload next fold to GPU via DqnGpuData::upload() so
  next fold starts with data already resident on GPU

2478 tests pass, 0 clippy warnings, 0 compile errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
a454a26a5c feat(ml): GPU saturation backlog — PPO rollout sync, VRAM-aware dims, KAN GPU splines
Three remaining GPU bottlenecks from the saturation backlog:

1. PPO rollout GPU sync stalls (3→1 per step):
   - Merged sample_action to return (action_idx, probs_vec), eliminating
     duplicate to_vec1 sync on action probabilities
   - Batched critic forward after rollout loop — single GPU→CPU sync
     replaces per-step critic.forward() calls (2048 syncs → 1)
   - Safe indexing throughout (clippy deny rules)

2. VRAM-aware default network dimensions:
   - Added detect_vram_mb() with GPU_MEMORY_MB env var override for K8s
   - Added vram_scaled_hidden_dims() with 4 tiers (CPU/<8GB/16GB/40GB+)
   - DQN: [256,256] → [2048,1024,512] on L40S/H100
   - PPO: hidden_dim_base 128 → 1024 on L40S/H100
   - Wired into train_baseline_rl.rs for non-hyperopt training runs

3. KAN B-spline GPU lookup table:
   - Pre-compute basis values on 1024-point grid at layer construction
   - GPU evaluation via gather + linear interpolation (replaces recursive
     Cox-de Boor CPU bounce: 32K recursive calls → 2 GPU gathers)
   - Fallback to CPU path when grid not pre-computed

5 files changed, +687/-43, 2476 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
2aedc2ae1a feat(ml): comprehensive GPU saturation audit — 58 fixes across all 10 models
Phase 1 — Fix broken models (P0):
- Diffusion: wire optimizer_step to actually apply gradients (was no-op)
- TLOB: connect forward pass to projection layers (was Tensor::zeros)
- Mamba2: F64→F32 migration across 5 files (~30x faster on L40S tensor cores)

Phase 2 — Eliminate hot-path GPU sync stalls:
- Mamba2: keep dt on GPU in discretize_ssm (4 functions, no CPU round-trip)
- TFT: gate attention weight logging to eval only (8 syncs/forward eliminated)
- Mamba2: defer loss scalar after backward (pipeline stall removed)
- Mamba2: delete dead gradient clipping (4N wasted GPU syncs removed)

Phase 3 — Enable BF16 for supervised models:
- Flip mixed_precision defaults to true in 4 config locations
- Fix cuda_layer_norm to support BF16/F16 via F32 intermediate

Phase 4 — Raise hyperopt bounds for datacenter GPUs:
- 7 adapters with VRAM-aware tiers (TFT, Liquid, TGGN, KAN, xLSTM,
  Diffusion, TLOB) — L40S gets full hidden_dim range
- Fix L40S tier boundary (was excluded at <48000, now >=40000)

Phase 5 — Update memory estimates:
- 10 param_count estimates updated (DQN 200K→12M, TFT 2M→50M, etc.)
- Fix power-of-two rounding (was wasting up to 49% of budget)
- Correct MODEL_OVERHEAD_MB in DQN/PPO/TFT adapters

Phase 6 — Fix per-epoch CPU bottlenecks:
- PPO: deduplicate double advantage normalization (correctness fix)
- PPO: GPU tensor reward normalization + explained variance
- Fuse per-parameter grad norm to single GPU sync (xLSTM, KAN, TGGN)

Phase 7 — Data pipeline:
- GpuBufferPool: use from_slice (eliminate staging buffer copy)

Phase 8 — Correctness:
- TFT: remove broken .detach() in forward_checkpointed (restore gradients)
- Update stale RTX 3050 Ti doc references

33 files changed, 2451 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:41:23 +01:00
jgrusewski
b4dc9766f9 fix(infra): remove dead Cockpit remote_write from GitLab Prometheus
The remoteWrite block had placeholder values (COCKPIT_METRICS_PUSH_URL,
COCKPIT_PUSH_TOKEN) that were never replaced, causing Prometheus to
spam "Failed to send batch" warnings every minute. Cockpit was replaced
by self-hosted Grafana+Prometheus+Loki+Tempo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:26:17 +01:00
jgrusewski
d501d53c9d chore(infra): remove dead Cockpit TF, CI-CD dashboards, stale Grafana configs
- Delete infra/modules/cockpit/ and infra/live/production/cockpit/
  (Scaleway Cockpit replaced by self-hosted Grafana+Prometheus+Loki+Tempo)
- Delete CI-CD dashboards (foxhunt-ci-pipelines, gitlab-services) and
  grafana-dashboards-cicd ConfigMap from K8s
- Delete config/grafana/ — unreferenced old dashboards (15 files)
- Delete config/monitoring/grafana/ — unreferenced DQN staging dashboard
- Delete crates/ml/grafana/ — unreferenced ML performance dashboard
- Delete services/broker_gateway_service/grafana/ — unreferenced
- Delete .claude/agents/devops/ci-cd/ — GitHub Actions agent (we use GitLab CI)
- Fix grafana-values.yaml: dashboard folder GitLab → Foxhunt,
  hardcoded adminPassword → K8s secret (grafana-admin),
  gitlab-overview → node-exporter (correct name for gnetId 1860)
- Remove CI-CD group from import.sh ConfigMap groups and API fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:13:40 +01:00
jgrusewski
36d291a8e0 fix(fxt): robust ibapi handshake retry and config test isolation
- ibapi handshake: retry once after 1s on first failure (IB Gateway
  needs time to release stale client_id slots after disconnection)
- test_load_nonexistent_config → test_load_config_succeeds: remove
  default-value assertions that fail when ~/.foxhunt/config.toml exists
  (defaults already tested by test_serde_defaults and test_default_config)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:52:48 +01:00
jgrusewski
032be46e90 fix(fxt): default broker gateway URL 50060 → 50056
Match the actual K8s broker-gateway service port discovered during
live validation of fxt broker check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:49:23 +01:00
jgrusewski
47cea06e86 fix(fxt): default broker check port 4002 → 4004 (socat)
The IB Gateway JVM uses non-blocking I/O on port 4002, which causes
EAGAIN errors with ibapi's blocking Client::connect(). The gnzsnz
image provides socat on port 4004 as a stable proxy that bridges
blocking clients to the non-blocking gateway socket.

Port 4004 is the correct client-facing port for paper mode (4003 for
live). The K8s readiness probe stays on 4002 since TCP probes work
fine with non-blocking sockets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:43:32 +01:00
jgrusewski
d0b896b01c fix(infra): probe TWS API port 4002, use Recreate strategy
Readiness/liveness probes were checking port 4004 (socat), which
always listens even when the gateway is stuck at login — masking
failures. Now probes check port 4002 (TWS API), which only opens
after successful IBKR authentication.

Deploy strategy changed to Recreate because IBKR allows only one
session per account. RollingUpdate starts the new pod before killing
the old one, causing both to fight over the session in a crash loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:37:51 +01:00
jgrusewski
13be624220 fix(infra): add EXISTING_SESSION_DETECTED_ACTION to IB Gateway
The gnzsnz/ib-gateway image renders its IBC config.ini from a template
using envsubst. The ExistingSessionDetectedAction field was rendering
as empty, causing IBC to show a GUI dialog when IBKR detected a
competing session — which nobody could dismiss in a headless pod.

Setting primaryoverride tells IBC to automatically take over any
existing session, which is the correct behavior for a K8s deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:26:10 +01:00
jgrusewski
e0a9dcfb60 Merge branch 'worktree-fxt-broker-check' 2026-03-02 14:02:50 +01:00
jgrusewski
ea130bdb52 chore(fxt): suppress unused_crate_dependencies for ibapi
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:53:02 +01:00
jgrusewski
7dbecf2b64 feat(fxt): wire broker check subcommand into CLI
Add Broker variant to Commands enum with BrokerArgs (flatten),
route to execute_broker_command in match block (no JWT required),
exit(1) on check failure. Clone config.api_gateway_url to avoid
partial move. Add two CLI parsing tests for broker check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:49:43 +01:00
jgrusewski
33208c928c feat(fxt): add broker check command with config resolution and connectivity checks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:44:20 +01:00
jgrusewski
9afd985a34 feat(fxt): compile broker_gateway.proto for gRPC client stubs
Copy broker_gateway.proto from broker_gateway_service into fxt/proto/
and wire it into build.rs compile_protos + lib.rs proto module so the
CLI can call BrokerGatewayService RPCs (health check, account state,
session status).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:37:49 +01:00
jgrusewski
ec23919c97 feat(fxt): add BrokerConfig section to TliConfig
Adds IbkrConfig (host/port/client_id with defaults for paper trading)
and BrokerConfig (gateway_url + ibkr nested) to the TLI config file.
Both structs derive serde defaults so existing config files remain
backward-compatible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:36:35 +01:00
jgrusewski
9e42c9264a feat(fxt): add ibapi optional dep behind broker-check feature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:33:43 +01:00
jgrusewski
eefb191a62 docs: add implementation plan for fxt broker check command
7 tasks: deps → config → proto → broker.rs → main.rs wiring → lint → verify.
TDD approach with exact file paths and commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:28:51 +01:00
jgrusewski
50d1aff97c docs: add design for fxt broker check CLI command
Two-layer IBKR connectivity validation: direct ibapi handshake +
broker-gateway gRPC health check. Pure-client architecture using
ibapi as optional dep on fxt (not trading_engine).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:26:17 +01:00
jgrusewski
0c1ac34fd9 chore(infra): delete gpu-idle-reaper CronJob (redundant)
Kapsule autoscaler already handles GPU node scale-down
(10min idle timeout). This CronJob only printed a message
and served no purpose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:04:39 +01:00
jgrusewski
03fa993d54 chore(grafana): rotate admin password to random value
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:02:21 +01:00
jgrusewski
216240bcd5 feat(grafana): migrate from SQLite/PVC to PostgreSQL backend
Grafana now stores users, preferences, and state in our existing
PostgreSQL instance (dedicated 'grafana' database). This eliminates
the 2Gi PVC dependency — all persistent state lives in Postgres,
dashboards in ConfigMaps, datasources in Helm values.

Also adds Grafana to Postgres NetworkPolicy ingress allowlist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:01:11 +01:00
jgrusewski
c608e62082 fix(grafana): restore full values file with sidecar, datasources, tolerations
The Grafana PVC was lost during cleanup (orphaned PV deletion).
Dashboards survived (ConfigMap-based), but user accounts and
datasources were lost.

This commit captures all Helm values previously set via --set:
- Sidecar config with foldersFromFilesStructure for folder organization
- Loki + Tempo datasources alongside Prometheus
- Platform node toleration for gitlab taint

Also fixed CI/CD folder annotation (slash caused nested directory).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:33:42 +01:00
jgrusewski
6e03c01e2c chore(infra): remove dead TF code — ci-rl pool and binaries S3 bucket
ci-rl pool was permanently disabled (enable_ci_rl_pool=false), all
training consolidated on ci-training (L40S). foxhunt-binaries S3
bucket was never created — binaries now deploy via shared PVC.

Also: deleted orphaned infra/live/production/ci-runner/ directory,
cleaned up stale Grafana ReplicaSets, recreated missing grafana PVC,
deleted orphaned Released PV, synced runner Helm configmap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:22:59 +01:00
jgrusewski
3050c7c424 fix(netpol): allow DNS + egress for CI executor pods
CI executor pods (label foxhunt-ci) were selected by allow-monitoring-scrape
(which uses matchExpressions In [foxhunt, foxhunt-ci]) making them
policy-controlled, but allow-dns only selected foxhunt pods via matchLabels.
This blocked DNS resolution → git clone failure in deploy jobs.

- Update allow-dns podSelector to matchExpressions In [foxhunt, foxhunt-ci]
- Add ci-egress policy granting broad egress for ephemeral CI pods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:56:44 +01:00
jgrusewski
d63190b9b9 feat(ml): GPU full saturation — remove artificial caps and enable VRAM-aware scaling
Phase 1: Remove artificial caps
- TFT benchmark: VRAM-scaled batch sizes (4/16/32/64) replacing hardcoded max_batch=4
- Liquid CUDA: VRAM-aware config defaults (batch 256-2048, pool 10% VRAM)
- DQN trainer: remove double-clamp between AutoBatchSizer and HardwareBudget

Phase 2: Mixed precision in training
- DQN agent: add BF16/FP16 dtype casting in forward_with_gradients and
  forward_without_gradients (training was bypassing forward_mixed)

Phase 3: Reduce CPU round-trips
- DQN trainer: flat buffer select_actions_batch (eliminate Vec<Vec<f32>>)
- DQN trainer: early-skip experience extraction (avoid .to_vec() on invalid)
- EpochPrefetcher: AtomicBool is_ready() so callers can detect completion

Phase 4: Adaptive scaling
- HardwareBudget: tiered safety factor (0.70-0.85 by GPU size)
- AutoBatchSizer: VRAM-proportional batch_overhead_mb (1.5% instead of fixed 250MB)

2451 tests pass, 0 clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:42:38 +01:00
jgrusewski
a489e6455e chore(infra): delete 8 per-service binary-cache PVCs (replaced by foxhunt-binaries)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:20:03 +01:00
jgrusewski
7b89a7256a feat(ci): deploy binaries via kubectl cp to shared PVC instead of S3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:11:49 +01:00
jgrusewski
1a104e4146 feat(infra): remove initContainers, mount shared foxhunt-binaries PVC
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:10:59 +01:00
jgrusewski
e3b9c2e097 chore(ci): remove write-manifest job (S3 tracking no longer needed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:10:50 +01:00
jgrusewski
78e6a7cc72 feat(ci): replace S3 upload with CI artifacts in build-web-dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:10:23 +01:00
jgrusewski
f80c5bbf8a feat(ci): replace S3 upload with CI artifacts in compile-services
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:09:55 +01:00
jgrusewski
395a7c3501 feat(infra): add shared foxhunt-binaries PVC (2Gi)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:08:11 +01:00
jgrusewski
56374a43ac feat(ml): VRAM-aware hidden dimension scaling for datacenter GPUs
DQN and PPO trainers now resolve hidden_dim_base from GPU VRAM when no
explicit override is given, so L4/L40S/H100 GPUs use proportionally
larger networks instead of being stuck at RTX 3050 Ti defaults (256).

- Add resolve_hidden_dim_base() tiered lookup (256/512/768/1024 by VRAM)
- Add network_param_count() for accurate model size estimation
- DQN: pre-compute hidden dims, use real param count for batch sizing
- PPO: add hidden_dim_base field, VRAM resolution in PpoTrainer::new()
- PPO hyperopt: raise hidden_dim_base ceiling from 2048 to 4096
- TFT hyperopt: expand hidden_sizes from [128,256,512] to 5 tiers
- Update stale estimates (DQN 50K→200K, PPO 100K→400K params)
- Fix pre-existing clippy lints in prefetch.rs and ppo.rs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:02:56 +01:00
jgrusewski
d35f4e0565 docs: binary cache PVC consolidation design (8 PVCs → 1 shared)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:58:33 +01:00
jgrusewski
c86743f7eb infra: rename services → foxhunt pool in all K8s manifests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:50:44 +01:00
jgrusewski
d6d8054759 infra: migrate MinIO to platform pool with data migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:37:49 +01:00
jgrusewski
b3cc52c13a infra: migrate QuestDB to platform pool (fresh start)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:22:57 +01:00
jgrusewski
5084dcd3b2 infra: migrate Postgres to platform pool with PVC migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:21:20 +01:00
jgrusewski
17091500ed infra: move Grafana to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:15:39 +01:00
jgrusewski
a9edd4c0b3 infra: move monitoring stack (loki, tempo, kube-state-metrics, pushgateway) to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:08:28 +01:00
jgrusewski
fea630e9ff infra: move tailscale proxies to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:08:20 +01:00
jgrusewski
70672f9878 infra: move Redis to platform pool
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:07:58 +01:00
jgrusewski
58f8478320 infra(tf): add platform pool, rename services → foxhunt in Kapsule module
Terraform changes for 3-pool node split:
- New `platform` pool resource (DEV1-L, databases + monitoring)
- Renamed `services` → `foxhunt` pool (DEV1-L, max_size 1)
- Updated variables, outputs, and live terragrunt inputs
- Updated implementation plan with Terraform-based workflow

Apply in 2 phases:
  Phase 1: terragrunt apply -target=scaleway_k8s_pool.platform
  Phase 2: terragrunt apply (after databases migrated to platform)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:59:21 +01:00
jgrusewski
9942ba8c29 docs: 3-pool node split implementation plan
11-task step-by-step plan: create platform pool, move monitoring
(stateless), migrate databases (PVC migration with backups), scale
services pool to 1 node. Includes verification and rollback procedures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:54:28 +01:00
jgrusewski
4da3a16bfe docs: 3-pool node split design (gitlab/platform/foxhunt)
Isolate platform infra (postgres, redis, minio, monitoring) from foxhunt
app services on separate DEV1-L nodes. Same EUR 61/mo total cost, better
blast radius containment and burst headroom for trading services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:49:46 +01:00
jgrusewski
d87c1cf21f feat(grafana): replace GPU gauges with timeseries, add CPU/Memory side-by-side
Infrastructure Cockpit:
- GPU gauges → side-by-side timeseries (GPU Utilization + GPU VRAM with total line)
- Added Memory by Service timeseries next to existing CPU by Service
- Cluster resource gauges shrunk to h=4 for tighter layout

Training Cockpit:
- GPU Utilization/Memory gauges → side-by-side timeseries matching infra cockpit
- GPU Temperature/Power widened from w=6 to w=12 in paired row

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:04:24 +01:00
jgrusewski
d8a1fa8a42 fix(grafana): show 'Inactive' instead of red on Trading Cockpit when not trading
6 stat panels (Ensemble Agreement, Prediction Confidence, Model Accuracy,
Ensemble Sharpe, Realized PnL, Unrealized PnL) showed red when ML metrics
don't exist yet. Added special null mapping → "Inactive" in dark-blue.
Panels will still show red/yellow/green when the trading system is active
and emitting metrics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:40:40 +01:00
jgrusewski
d6c65f69bd fix(grafana): fix CI dashboard showing red when idle
The "Active CI Jobs" stat panel used sum(gitlab_ci_active_jobs_sum) which
is a histogram accumulator that only grows (was showing 982 red). Changed
to sum(increase(pipeline_processing_events_total[1h])) which shows actual
pipeline activity in the last hour. Threshold changed to blue=idle,
green=active.

Also fixed Grafana provisioning:
- Removed overlapping named providers (cockpits/operations/infrastructure/cicd)
  that duplicated sidecarProvider, causing UID conflicts and write lockout
- Enabled foldersFromFilesStructure on sidecarProvider
- Unlabeled grafana-dashboards-foxhunt ConfigMap (duplicate of cockpits+operations)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:27:53 +01:00