Gravity Labs FSD
Complete functional specification and technical design for the Gravity Labs platform. Covers architecture, cloud abstraction, subscription engine, AI agent implementation, API design, and data models.
System Architecture Overview
Cloud-native, horizontally scalable platform built around a cloud-abstraction layer enabling deployment on Azure, AWS, GCP, or on-premises Kubernetes. All application logic is cloud-agnostic; cloud-specific behaviour is encapsulated in adapter modules selected at startup.
| Layer | Components | Technology Options |
|---|---|---|
| Presentation | Participant Portal, Admin Portal, Super Admin, Public Site | React 18 + TypeScript + Tailwind CSS. White-label themeable via CSS variables. |
| API Gateway | Rate limiting, auth, routing, API key management | Nginx Ingress (current) · Azure APIM (Azure) · Kong (on-prem) |
| Application Backend | REST API, business logic, HITL workflow state, RBAC | FastAPI (Python 3.11), async, 3+ replicas via Kubernetes Deployment |
| AI Agent Orchestration | 8 agents, HITL gates, LangGraph stateful pipelines | LangGraph (Python). Claude API (primary) / Azure OpenAI GPT-4o (MLP-compliant) |
| Subscription Engine | License Manager, Subscription Monitor, credit metering | FastAPI microservice. Microsoft Graph API, GitHub API, Databricks API, CSP REST API |
| Lab Orchestration | Provisioning queue, warm pool manager, environment lifecycle | Temporal.io (on-prem portable) · Azure Service Bus / AWS SQS / RabbitMQ |
| Compute — Containers | Code-Server, GPU notebook labs | AKS / EKS / GKE / vanilla K8s. KEDA autoscaling. |
| Compute — VMs | Full Windows/Linux VM labs, warm pool | Azure VMSS / AWS EC2 ASG / GCP GCE MIGs / VMware vSphere. Packer for images. |
| Compute — Azure Sandbox | Ephemeral Azure tenant, capped subscription per participant | Azure Subscription Pool. ARM/Bicep deployment. Azure Budget + Policy hard deny cap. |
| Streaming Gateway | Browser-to-desktop streaming for VM and GUI labs | Apache Guacamole (RDP/VNC/SSH) + Neko WebRTC (GPU/GUI) + Code-Server HTTPS |
| Data | User data, event data, scores, subscriptions | PostgreSQL (OLTP) + Redis (session cache, warm pool) + Cloud Object Storage |
| Observability | Metrics, logs, traces, alerts | Prometheus + Grafana + Loki (AKS) · Azure Monitor / CloudWatch (cloud-managed) |
All workloads run inside a private VNet/VPC. No workload has a direct public IP. VM lab networks are fully isolated from each other and from the application network. Azure Portal Sandbox tenants are completely separate Azure tenants — zero network connectivity to the GL platform tenant.
Cloud Abstraction Layer
Python abstract base classes define all cloud-dependent operations. At startup the deployment target is read from gravity-labs.config.yaml and the correct adapter implementations are loaded dynamically.
| Interface | Azure | AWS | On-Premises |
|---|---|---|---|
IComputeProvider | AKS + VMSS; azure-mgmt-compute SDK | EKS + EC2 ASG; boto3 | K8s Python client + pyVmomi (vSphere) |
IIdentityProvider | Entra ID; MSAL Python + Graph API | AWS Cognito; boto3 cognito-idp | Keycloak 23; python-keycloak + ldap3 |
IStorageProvider | Azure Blob Storage; azure-storage-blob | S3; boto3 + presigned URLs | MinIO; minio Python client |
ISecretStore | Azure Key Vault; azure-keyvault-secrets | AWS Secrets Manager; boto3 | HashiCorp Vault 1.15; hvac Python |
IMessageQueue | Azure Service Bus; azure-servicebus | SQS; boto3 sqs client | RabbitMQ; aio-pika · Kafka (high-throughput) |
IObservability | Azure Monitor + App Insights; OTel exporter | CloudWatch; OTel AWS contrib | Prometheus + Grafana + Loki; OTel Prometheus |
gravity-labs.config.yaml
Single configuration file that controls all cloud-specific behaviour. Switching deployment targets requires only editing this file — no code changes required.
Subscription Engine — Internal API
Dedicated FastAPI microservice (subscription-engine, 2+ replicas). PostgreSQL for records. Redis for real-time credit usage (30-second polling, served instantly to dashboards).
| Endpoint | Method | Description |
|---|---|---|
/api/v1/subscriptions/manifest | POST | Agent submits lab blueprint. Returns full subscription manifest with quantities and total event cost for admin HITL review. |
/api/v1/subscriptions/approve | POST | Admin approves (or modifies) manifest. Triggers bulk procurement. Records approver and timestamp in audit log. |
/api/v1/subscriptions/provision/{session_id} | POST | Called by Provisioning Agent on lab start. Activates all approved licenses for this participant session. |
/api/v1/subscriptions/usage/{session_id} | GET | Returns real-time credit usage. Served from Redis. Polled every 30 seconds by participant Subscription Dashboard. |
/api/v1/subscriptions/topup | POST | Participant submits top-up request. Fires admin notification within 30 seconds. |
/api/v1/subscriptions/topup/{id}/approve | POST | Admin approves top-up. Increases credit cap via Azure Budget API. Refreshes Redis cache immediately. |
/api/v1/subscriptions/revoke/{session_id} | POST | Called on session termination. Revokes all licenses, deactivates Azure subscription, destroys ephemeral Entra ID user. 100% within 5 minutes. |
Azure Portal Sandbox Provisioning
Pool of pre-created Azure subscriptions. Each tagged with pool status. Auto-scales when available count drops below low-water mark. 30-minute quarantine after session end before returning to pool.
- Portal URL: portal.azure.com
- Username: user-[code]@[tenant].onmicrosoft.com
- Temporary password (auto-generated)
- Subscription ID + Resource Group name
- Credit cap, current balance, session expiry time
- AZ-104: Azure Administrator
- AZ-305: Azure Solutions Architect
- AZ-500: Azure Security Technologies
- AZ-700: Azure Network Engineer
- DP-203: Azure Data Engineer
- SC-300: Identity & Access Administrator
Real-Time Credit Metering Pipeline
Asyncio background task polls all active sessions every 30 seconds. Results stored in Redis with 60-second TTL. Participant dashboard polls usage endpoint for near-real-time display.
- Azure: Cost Management REST API for subscription spend
- GitHub: Usage API for Actions minutes + Copilot seats
- Databricks: REST API for DBU consumption
- Snowflake: REST API for credit consumption
- 80% of credit cap: Amber alert in participant dashboard + admin notification via WebSocket + email
- 100% of credit cap: Red alert + "Request More Credits" prompt + admin notification. Azure Policy deny blocks all further spend.
HITL Agent Workflow — LangGraph Design
The lab creation workflow is a LangGraph stateful graph. Three HITL gate nodes pause execution, persist state to PostgreSQL, notify the admin, and await explicit human approval before resuming.
Agent Technical Specifications
Purpose: NL description → validated Lab Manifest for Gate 1.
RAG Index: Azure AI Search index of MS FY26 course catalogue (70+ cert tracks), known lab patterns, subscription SKU catalogue with pricing. Updated monthly.
Failure handling: Pydantic validation failure → retry up to 3 times with validation error fed back in prompt. After 3 failures: alert admin, return partial manifest for manual completion.
Generation: Faker 19 + Pandas 2 + NumPy 1.26. Unique seed per participant: seed = hash(event_id + participant_id). Parallel via multiprocessing.Pool.
Uniqueness Check: Pairwise Pearson correlation on key numeric columns. If any pair has r > 0.95: regenerate with adjusted seed. Max 3 retries.
Storage path: datasets/{event_id}/{participant_id}/dataset.parquet
Routing logic:
code_workspace→ AKS + Code-Serverfull_vm_windows→ VMSS + Guacamole RDPfull_vm_linux→ VMSS + Guacamole SSHazure_portal_sandbox→ Subscription Poolgpu_lab→ GPU AKS + Jupyterbrowser_desktop→ container + Neko WebRTC
Warm Pool: Atomic POP from Redis (< 1 second). Cold provision fallback: 20–40 seconds.
| Check | Pass Criteria |
|---|---|
| Connectivity | Streaming handshake < 10s |
| Subscription | All licenses status=active |
| Dataset | DATASET_URL set, schema valid |
| Tool Install | All tools launchable |
| Network Isolation | Cannot reach other participant's IP |
Output: Green / Amber / Red per check. Red = hard failure, Gate 3 blocked.
Activity signals: Container labs: shell command log stream. VM labs: Guacamole keystroke/mouse event stream. Azure sandbox: Azure Activity Log resource events.
Idle detection: No activity > 5 minutes → trigger Hint Agent. Idle > 15 minutes → admin alert in Proctor View.
Progress estimation: LLM estimates which task participant is working on. Updates Proctor Dashboard in real-time.
Trigger: Live Observer idle threshold exceeded, or participant clicks "Get Hint".
Prompt principle: "Provide one specific, actionable hint. Do NOT give the answer. Max 2 sentences. Be contextual to what they appear to be attempting."
Score impact: Each hint deducts 2% from Independence dimension (max 10% total). Participant sees penalty warning and must confirm before hint is delivered.
5-Dimension Scoring Model
Scoring & Assessment Agent evaluates each submission against 5 dimensions. Cross-Validation Agent then tests the solution against 2–3 unseen reserve datasets to verify genuine skill generalisation.
| Dimension | Weight | Evaluation Method |
|---|---|---|
| Functional Correctness | 40% | Automated test suite. Azure sandbox: Azure Resource Graph API to verify required resources exist with correct config. Code labs: test scripts against submitted code. |
| Architectural Quality | 20% | LLM evaluation of architecture: least privilege, naming, resource organisation, tagging, service selection rationale. Scored against rubric from Lab Manifest. |
| Resource Efficiency | 15% | Azure Advisor recommendations against participant's subscription. Score based on right-sizing, unused resources, and cost optimisation suggestions identified. |
| Robustness (Cross-Validation) | 15% | Cross-Validation Agent tests submission against 2 additional unseen datasets. Pass rate = robustness score. Ensures solution generalises beyond participant's own dataset. |
| Speed & Independence | 10% | Time to complete minus hint penalty deductions. Normalised against event median completion time. |
Uses 2–3 reserve datasets per lab (generated by Dataset Forge but withheld from participants). Runs submitted solution against each reserve dataset. Pipeline completes within 3 minutes of submission. Results fed into final score calculation and narrative score report with certification exam objective mapping.
API Specification
Admin and Participant portals: JWT bearer tokens (RS256) issued by IIdentityProvider. External integrations: API key in X-API-Key header. LTI 1.3: OAuth 2.0 PKCE flow for grade passback. API returns HTTP 403 if a workflow advances to the next stage without passing all prior HITL gates — enforced at API layer, cannot be bypassed.
Lab Lifecycle Endpoints
| Endpoint | Method | Request / Response |
|---|---|---|
/api/v1/labs/start | POST | Body: { event_id, participant_id } → { session_id, environment_type, access_url, credential_card?, expires_at } |
/api/v1/labs/{session_id}/status | GET | { status: provisioning|ready|active|terminated, progress_pct, streaming_url, subscription_summary } |
/api/v1/labs/{session_id}/submit | POST | multipart/form-data { artifacts[], notes } → { submission_id, estimated_score_ready_in_seconds } |
/api/v1/labs/{session_id}/score | GET | { dimensions: {correctness, architecture, efficiency, robustness, independence}, total_score, narrative_feedback, exam_objective_mapping } |
/api/v1/labs/{session_id}/terminate | POST | Triggers environment cleanup, license revocation, subscription quarantine. → { status: terminating, cleanup_eta_seconds } |
/api/v1/events/{event_id}/leaderboard | GET | { rank, participant_display_name, total_score, completion_time, hint_count }[] |
Admin / Workflow Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/admin/labs/generate | POST | Start HITL workflow. Body: LabRequest → { thread_id, status: awaiting_gate_1 } |
/api/v1/admin/workflows/{id}/gates/1/approve | POST | Gate 1 approval with optional manifest edits. Triggers dataset preview + subscription manifest. |
/api/v1/admin/workflows/{id}/gates/2/approve | POST | Gate 2 approval. Triggers procurement + dataset generation. |
/api/v1/admin/workflows/{id}/gates/3/approve | POST | Gate 3 launch approval. Makes event live → { event_id, status: live } |
/api/v1/admin/events/{event_id}/sessions | GET | All sessions with status, progress, subscription credit usage, hint count, current task estimate. |
/api/v1/admin/events/{event_id}/cost | GET | Real-time cost: total, per-participant avg, by subscription type, budget vs actual. |
/api/v1/admin/pool/resize | POST | Resize warm VM pool or Azure subscription pool. |
Core PostgreSQL Schema
On-Premises Deployment Requirements
| Component | Minimum Spec | Notes |
|---|---|---|
| Kubernetes Cluster | 3 control-plane + 5+ worker nodes, 8 vCPU / 32GB RAM each | K8s 1.28+, OpenShift 4.12+, Rancher/RKE2. Helm 3.10+ required. |
| VMware vSphere | vSphere 7.0+; ESXi hosts with 32+ vCPU / 128GB RAM | pyVmomi SDK for VM provisioning/clone/destroy from golden OVA templates. |
| MinIO (Object Storage) | 500GB NFS-backed PVC | S3-compatible API. Same IStorageProvider adapter code as AWS S3. |
| Keycloak (Identity) | 2 clustered instances, 2 vCPU / 4GB RAM each | LDAP/AD federation. SAML/OIDC for portal SSO. |
| HashiCorp Vault (Secrets) | 3-node HA Raft cluster | Auto-unseal via HSM if available. Kubernetes auth method for pod identity. |
| RabbitMQ / Kafka | 3-node cluster | RabbitMQ for provisioning queues. Kafka for high-throughput agent telemetry. |
| Prometheus + Grafana + Loki | 2 vCPU / 8GB RAM per node | Pre-built Gravity Labs dashboards included in Helm chart. |
| Container Registry | Harbor or JFrog Artifactory | Replaces ACR/ECR/GCR. All images pre-loaded for air-gapped operation. |
| PgBouncer | 2 vCPU / 2GB RAM | Connection pooler in front of PostgreSQL. Transaction pooling mode. Essential for 1,000+ concurrent sessions. Set statement_cache_size=0 in SQLAlchemy for PgBouncer compatibility. |
Security Model
- JWT bearer tokens (RS256) — Phase 2 upgrade from HS256
- Access token TTL: 15 minutes
- Refresh token TTL: 7 days, JTI stored in Redis
- JTI blocklist checked on every request
- Dummy bcrypt on unknown email (prevents timing attacks)
- Per-IP rate limiting via Redis SETNX + EXPIRE
- All workloads in private VNet/VPC — no direct public IPs
- Azure Key Vault / HashiCorp Vault for all secrets
- Managed Identity for pod-to-service authentication
- Network Security Groups (NSG) per subnet
- Private Endpoints for all PaaS services
- RBAC enforced at API layer AND Kubernetes RBAC
- Each participant lab in a separate private subnet
- Azure Portal Sandbox: completely separate Azure tenant
- Network isolation verified by QA Validator Agent before launch
- Guacamole session recording for compliance labs
- All agent decisions audit-logged with approver + timestamp
- SOC 2 Type II + ISO 27001 compliance evidence packages
Data Layer — PostgreSQL + Redis + PgBouncer
Single PostgreSQL 16 instance in AKS, multiple logical databases (one per service). PgBouncer in front for connection pooling. Redis for all ephemeral stateful data.
SQLAlchemy compatibility: set statement_cache_size=0 in connect_args.
- 25K-user event: 2,000+ simultaneous app connections
- PostgreSQL default
max_connections: 100 - PgBouncer multiplexes 2,000 app connections into 20 real Postgres connections
- KEDA scale-out: 300 scoring-agent pods × 2 connections = 600 new connections in 90s — absorbed by PgBouncer without impacting Postgres
- Without PgBouncer: world-record event cannot run on a single Postgres instance