# Cloud World Model Platform - Full Reference Cloud World Model is a multi-cloud infrastructure simulation platform that lets developers, architects, and AI agents practice and test cloud infrastructure designs without provisioning real resources - and without cloud bills. It is a Canvas Cloud AI companion product. > Simulate the cloud without the cloud. Predict behavior, analyze cost and resilience, and train reinforcement learning agents across AWS, GCP, Azure, OCI, and DigitalOcean - all in a safe, cost-free environment. --- ## Product Overview - **Platform type**: Full-stack TypeScript web application (React/Vite frontend, Express.js backend). - **Primary use cases**: - Cloud architecture education and hands-on practice (no real cloud bills). - AI/RL agent training for autoscaling and infrastructure optimization. - Chaos engineering and resilience testing. - Multi-cloud strategy evaluation and cost comparison. - Predictive capacity planning and threshold optimization. - **Simulation engine**: Capacity-aware, resource-specific performance profiles. Calculates CPU usage, error rates, throughput, connection pool pressure, and provider-specific hourly costs. - **AI explanations**: Powered by OpenAI GPT-5. Explains bottlenecks, autoscaling behavior, and architecture optimizations. Supports a beginner mode with simplified language. - **Hybrid prediction**: Combines deterministic rule-based simulation with ML-based prediction, blended via a weighted hybrid referee. --- ## Cloud Providers Supported | Provider | Compute | Database | Storage / Other | |---|---|---|---| | AWS | EC2 (t3, m5, c5, r5 families) | RDS, Aurora PostgreSQL (`aurora-postgresql`), Aurora DSQL (`aurora-dsql`), Aurora Serverless v2 (`aurora-serverless`), DynamoDB, ElastiCache | S3, CloudFront, ALB | | Google Cloud (GCP) | Compute Engine (e2, n2, c2 families) | Cloud SQL, Spanner, Bigtable, Memorystore | GCS, Cloud CDN, Cloud Load Balancing | | Microsoft Azure | Virtual Machines (B, D, F series) | Azure SQL, Cosmos DB, Cache for Redis | Blob Storage, Azure CDN, Application Gateway | | Oracle Cloud (OCI) | VM.Standard.E4.Flex, VM.Standard3.Flex, Container Instances | Autonomous Database (Standard/TP) | Object Storage | | DigitalOcean | Droplets (Basic, General Purpose, CPU-Optimized, Memory-Optimized) | Managed PostgreSQL, MySQL, Redis | Spaces Object Storage, Load Balancers | ### OCI Pricing Reference Configs (June 2026, us-ashburn-1) - VM.Standard.E4.Flex: 1 OCPU + 8 GB RAM = $0.037/hr - VM.Standard3.Flex: 1 OCPU + 6 GB RAM = $0.049/hr - Container Instances (E4.Flex ~0.5 OCPU + ~6 GB): ~$0.02/hr - Autonomous AI Standard (formerly Autonomous DB): 2 ECPUs + storage blended = ~$0.789/hr --- ## Pages - [Home](https://www.cloudworldmodel.ai/) - Platform overview and getting started - [Getting Started](https://www.cloudworldmodel.ai/getting-started) - Quickstart guide for new users; includes interactive 10-step tutorial - [Simulation API Walkthrough](https://www.cloudworldmodel.ai/simulation-walkthrough) - End-to-end developer tutorial chaining all core simulation API calls in sequence: create simulation, step, add a traffic pattern, inject a spike, read metrics history, get right-sizing hints - [Use Cases](https://www.cloudworldmodel.ai/use-cases) - Example use cases for learners and AI agents - [Workspace](https://www.cloudworldmodel.ai/workspace) - Visual canvas for building and simulating cloud architectures; drag-and-drop resource palette, real-time metrics dashboard, event log, simulation controls, and AI insights panel - [Scenarios](https://www.cloudworldmodel.ai/scenarios) - Pre-built and user-saved simulation scenarios - [Agents](https://www.cloudworldmodel.ai/agents) - RL agent dashboard, API key issuance and revocation, job monitoring - [Pricing](https://www.cloudworldmodel.ai/pricing) - Free tier (1,000 credits/month, no card required), credit packs (Small 10k/$9, Medium 100k/$49, Large 1M/$299), and cost per API call type - [Pricing History](https://www.cloudworldmodel.ai/pricing-history) - Historical and current cloud provider pricing data across all supported providers - [Billing](https://www.cloudworldmodel.ai/billing) - Credit balance, usage history, and Stripe-powered top-up - [Simulation Fidelity](https://www.cloudworldmodel.ai/fidelity) - Per-provider benchmark sources and stated accuracy ranges: cost ±10%, performance ±15%, calibrated against official AWS, GCP, Azure, OCI, and DigitalOcean pricing pages (June 2026). Lists every covered resource type, instance SKU, hourly rate, and official source URL. - [Supported Regions](https://www.cloudworldmodel.ai/regions) - All cloud regions supported by the simulator across AWS, GCP, Azure, OCI, and DigitalOcean — 177 regions with zone counts, locality type (Availability Zone / Zone / Availability Domain), and provider zone labels - [Benchmark Report](https://www.cloudworldmodel.ai/benchmark) - Full multi-cloud pricing and performance benchmark report comparing AWS, GCP, Azure, OCI, and DigitalOcean across compute, database, storage, and networking tiers - [Simulation Accuracy Benchmark](https://www.cloudworldmodel.ai/accuracy) - Side-by-side comparison of Cloud World Model simulation outputs vs. AWS reference metrics (P50/P95 latency, CPU, throughput, error rate, cost) for a canonical ALB → 2× m5.large EC2 → db.r5.large RDS MySQL architecture across four traffic scenarios (Idle 10 req/s, Normal 100 req/s, Peak 500 req/s, Burst 1,000 req/s). Composite accuracy score shown per scenario. Data endpoint: GET /api/accuracy-benchmark (public, no auth). - [RL Training Environments](https://www.cloudworldmodel.ai/rl/environments) - Reference guide for training reinforcement learning agents against the cloud simulator: covers the episode lifecycle (reset → step loop → done), the 7-action action space (scale_out, scale_in, adjust_threshold, add_resource, remove_resource, no_op, set_recovery_policy), the 6-field observation vector (rps, cpu_util, instances, traffic, currentTime, tick_seconds), the 5-metric evaluation output (cost_usd_hr, latency_p95, error_rate, uptime, sla_violations), and the reward signal (performance, cost, stability, sla, plus a connection_pressure DB-pool penalty when a database resource is present). Includes runnable multi-episode training-loop examples: Python (`examples/rl_training_loop.py`), JavaScript (`examples/rl_training_loop.js`), Fetch API (`examples/rl_training_loop_fetch.mjs`), TypeScript (`examples/rl_training_loop.ts`), Go (`examples/rl_training_loop.go`, stdlib only — `go run examples/rl_training_loop.go --token $API_KEY`). - [Provider Coverage](https://www.cloudworldmodel.ai/provider-coverage) - Every service, instance family, and pricing model the simulator models for each cloud provider. AWS: 16 EC2 instance types, 16 DB sizes (RDS/Aurora families), ALB, CloudFront, S3, EBS, Lambda, DynamoDB, ElastiCache. GCP: 10 Compute Engine types, Cloud SQL, Spanner, Bigtable, Firestore, Memorystore, Cloud Storage, Persistent Disk, Cloud Run, Cloud Armor. Azure: 10 VM types, Azure SQL (all tiers incl. MI), Cosmos DB, Redis, Blob Storage, Managed Disks, Azure Functions. OCI: 13 compute shapes incl. Bare Metal, MySQL HeatWave, Autonomous DB, Exadata, Block Volume, CDN, WAF. DigitalOcean: 20 Droplet types (Basic, Premium NVMe, CPU-Optimized), Managed DB/Redis/MongoDB/Kafka, DOKS, Spaces. All counts derived from live size arrays; base rates from official pricing constants (June 2026). Coverage snapshot version updated in COVERAGE_VERSION and validated against a 90-day freshness window in CI. - [Privacy Policy](https://www.cloudworldmodel.ai/privacy) - Privacy policy - [Terms of Service](https://www.cloudworldmodel.ai/terms) - Terms of service - [Blog](https://www.cloudworldmodel.ai/blog) - TODO: add description - [Blog/What We Learned Product Hunt](https://www.cloudworldmodel.ai/blog/what-we-learned-product-hunt) - Retrospective on the Product Hunt launch: key takeaways from finishing #5 Product of the Day and 100+ user comments - [Blog/X402 Cloud Simulation Api](https://www.cloudworldmodel.ai/blog/x402-cloud-simulation-api) - How we built native x402 payable API support so AI agents can run simulations and pay per request — no human-in-the-loop billing setup required. --- ## API Surface All external APIs are served under the `/api` prefix. Simulation creation and key management endpoints are public (no auth required for demo purposes). RL, chaos, multi-cloud, prediction, optimization, and AI analysis endpoints require a Bearer API key or an x402 payment header. Base URL: `https://www.cloudworldmodel.ai/api` ### x402 Pay-Per-Request — Discovery Summary Cloud World Model is an **x402-compatible seller** (x402 is a Linux Foundation open protocol). AI agents can call any metered endpoint without an account or API key by attaching an `X-PAYMENT` header and paying per call in USDC on the Base network. | Field | Value | |---|---| | Discovery endpoint | `GET /api/billing/x402/config` | | Network | `base` (Base, Ethereum L2) | | Asset | USDC | | No signup required | Yes — no account, no API key needed for x402 callers | | Balance lookup | `GET /api/billing/x402/balance?address=0x...` | | Transaction history | `GET /api/billing/x402/transactions?address=0x...&limit=50` | | x402scan listing | https://www.x402scan.com/server/1a8052f0-c764-420a-96a5-f50d3c696795 | Call `GET /api/billing/x402/config` first to read the live `payTo` wallet address, exact USDC amounts per call type, facilitator URL, and credits-per-USDC conversion rate before constructing any payment header. This endpoint is public and requires no authentication. **Per-use-case cost estimates** (based on current $0.0010/step and $0.0010/AI-analysis pricing; analysis jobs cost $0.0050): | Use case | Calls | Estimated cost | |---|---|---| | 100-step RL training loop | 100 × `rl_step` | ≈ $0.10 | | 1 000-step RL training run | 1 000 × `rl_step` | ≈ $1.00 | | AI explanation (explain) | 1 × `ai_explain` | $0.0010 | | AI optimization suggestions | 1 × `ai_optimize` | $0.0010 | | AI troubleshooting guide | 1 × `ai_troubleshoot` | $0.0010 | | AI bottleneck analysis | 1 × `ai_bottleneck` | $0.0010 | | Single chaos scenario | 1 × `chaos_run` | $0.0050 | | Batch of 20 chaos scenarios | 20 × `chaos_run` | $0.10 | | Multi-cloud cost comparison | 1 × `multicloud_explore` | $0.0050 | | Predictive scaling validation | 1 × `prediction_validate` | $0.0050 | | Hybrid simulation step | 1 × `simulation_step_hybrid` | $0.0010 | Always fetch `GET /api/billing/x402/config` for the authoritative live price table — the values above reflect current pricing but the config endpoint is the single source of truth. **Minimal Python agent snippet** (`httpx-x402` library): ```python import httpx from x402.httpx import wrap_httpx_client from x402.types import X402Config # 1. Discover live prices (no auth required) config = httpx.get("https://www.cloudworldmodel.ai/api/billing/x402/config").json() # 2. Wrap your httpx client with x402 auto-pay support client = wrap_httpx_client( httpx.Client(), private_key="0xYOUR_PRIVATE_KEY", # EVM wallet key — keep secret ) # 3. Call a metered endpoint — payment happens automatically on 402 response = client.post( "https://www.cloudworldmodel.ai/api/rl/environments/{env_id}/step", headers={"Content-Type": "application/json"}, json={"action": "scale_up"}, ) print(response.json()) # observation, reward, done ``` ### Authentication & Key Management | Method | Path | Auth | Description | |---|---|---|---| | POST | /keys | Public | Create a new API key; the raw key is returned once - store it securely | | DELETE | /keys/{keyId} | Public | Revoke an API key | **Key scopes**: `read`, `write`, `admin`. Default: `[read, write]`. ### Wallet Auth (EIP-191 sign-in — no API key required) Agents with an EVM wallet can authenticate without creating a traditional API key. The two-step flow issues a 24-hour JWT session token that can be used as a Bearer token on `GET /simulations` and `GET /simulations/{simulationId}`. **Flow:** call `POST /wallet-auth/challenge` with your wallet address → sign the returned `message` with `personal_sign` (EIP-191) → call `POST /wallet-auth/verify` with the signature → receive a `token` → use `Authorization: Bearer ` on simulation endpoints. | Method | Path | Auth | Description | |---|---|---|---| | POST | /wallet-auth/challenge | Public | Request an EIP-191 sign-in challenge (nonce + message to sign). Rate-limited: 10/min per IP. | | POST | /wallet-auth/verify | Public | Submit the EIP-191 signature to receive a 24-hour JWT session token. | | POST | /wallet-auth/x402-session | x402 micro-payment | Issue a 24-hour wallet session JWT via USDC micro-payment on Base (x402 protocol). Idempotent per transaction hash. Token validity survives restarts only when WALLET_AUTH_JWT_SECRET is set. | **Wallet session scope:** Read-only (`read`). The session can list and retrieve simulations that were claimed by the wallet address (`ownerWallet` field). `GET /simulations` returns a paginated object `{ simulations, total, limit, offset }` for wallet sessions (rather than a plain array for API-key sessions). Mutations (`POST`, `PATCH`, `DELETE`) still require an API key. ### Simulation API Create and manage simulations, step them forward, inject traffic or failures, read metrics and events, and call AI-powered analysis helpers. **Lifecycle** | Method | Path | Auth | Description | |---|---|---|---| | POST | /simulations | Public | Create a simulation with cloud resources (compute, database, storage, networking). Pass a Bearer token to assign ownership immediately and skip the claim step. | | GET | /simulations | Bearer (read) | List all simulations owned by the authenticated key | | GET | /simulations/{simulationId} | Bearer (read) | Get full simulation state (resources, time step, traffic, autoscaling history) | | PATCH | /simulations/{simulationId} | Bearer (write) | Partially update simulation properties (name, description, traffic, resources) | | DELETE | /simulations/{simulationId} | Bearer (write) | Delete a simulation and all associated data | | POST | /simulations/{simulationId}/claim | Bearer (write) | Claim ownership of an unowned demo simulation; returns 200 on success (idempotent if caller already owns it), 409 if owned by another key | **Ownership & expiry — read this before reusing simulation IDs** Simulations come in two flavours and the difference matters for any agent or tool that stores IDs: - **Owned (API-created) simulations are persistent.** A simulation created through `POST /api/simulations` with a Bearer token — or one you `claim` — is bound to your API key and **never expires**. These are the only simulations reachable through the authenticated `/api/simulations/*` API (including the `validate-*` endpoints). Treat the returned ID as the durable handle you manage. - **Unowned (browser-workspace / demo) simulations are ephemeral.** Simulations built interactively in the browser workspace have no API-key owner. They live only behind the session-cookie UI routes, are **never** reachable through the authenticated API, and **auto-expire after ~5 minutes**. Their IDs are not durable. **Claim-before-validate workflow.** To persist and then validate a simulation you built in the browser workspace, claim it *before it expires*: `POST /api/simulations/{simulationId}/claim` with a write-scoped Bearer token binds it to your key (idempotent if you already own it; `409` if another key owns it). Once owned, it stops expiring and the `validate-*` endpoints work on it. **Guidance for agents/tools.** Always **create (or claim) simulations through the API** and treat the returned ID as the thing you manage. **Do not reuse IDs from earlier browser/demo runs** — an unowned ID from a previous session has almost certainly expired. Hitting `GET /api/simulations/{id}` or any `validate-*` endpoint with such an ID returns `404 {"error":"Simulation not found or expired", "reason": "...", "remedy": "..."}`. The `remedy` field tells you to create an owned simulation via `POST /api/simulations` (or claim an unowned one). A `404` never confirms whether a simulation owned by a *different* key exists — a sim owned by another key returns `403 {"error":"Access denied"}` instead. **`validate-*` works on any owned simulation, of any complexity.** The cost/performance/combined validators map each resource to the nearest pricing & performance benchmark by provider + service family + size, so they work on hybrid, multi-provider, autoscaled, and post-chaos simulations — not just simple single-resource "fidelity match" sims. You do not need a special benchmark-shaped simulation to call them; any owned simulation you can `GET` can be validated. **Kubernetes cluster size — node-pool characteristics.** A resource with `type: "kubernetes"` models a managed container node pool (EKS / GKE / AKS / OKE / DOKS). Its size is set through three `characteristics` fields: | Field | Type | Description | |---|---|---| | `nodeCount` | number? | Current number of worker nodes in the node pool. The cluster's `maxThroughput` (serving capacity) and hourly cost scale proportionally with this count. | | `minNodes` | number? | Minimum worker nodes the pool will scale in to. Defaults to the provider's autoscaling profile minimum when omitted. | | `maxNodes` | number? | Maximum worker nodes the pool will scale out to. Defaults to the provider's autoscaling profile maximum when omitted. | During `/step` the autoscaler adds or removes worker nodes between `minNodes` and `maxNodes`, updating `nodeCount` in place and recomputing the cluster's `maxThroughput` and hourly cost (`perNodeRate × nodeCount`). Set `nodeCount` to size the cluster at creation; set `minNodes`/`maxNodes` to bound how far it can autoscale. **Multiple node pools per cluster.** For clusters with heterogeneous workloads, set `characteristics.nodePools` to an array of pool objects instead of the single-pool fields above. Each pool scales independently within its own bounds and is billed at its own per-node rate: | Field | Type | Description | |---|---|---| | `name` | string? | Human-readable node pool name (e.g. `general`, `gpu`). | | `nodeCount` | number? | Current number of worker nodes in this pool. Scales this pool's serving capacity and cost proportionally. | | `minNodes` | number? | Minimum worker nodes this pool will scale in to. Defaults to the provider's autoscaling profile minimum when omitted. | | `maxNodes` | number? | Maximum worker nodes this pool will scale out to. Defaults to the provider's autoscaling profile maximum when omitted. | | `perNodeRate` | number? | Hourly cost per node for this pool. Falls back to the provider default rate when omitted. | When `nodePools` is present, the legacy single-pool fields (`nodeCount`, `minNodes`, `maxNodes`) are ignored; when it is absent, the cluster behaves as a single pool described above. **Resource capacity tuning — `characteristics` fields.** Beyond the Kubernetes node-pool fields above, the `characteristics` object exposes several capacity knobs the simulation engine uses to model how a resource behaves under load. All are optional; sensible defaults apply when omitted. | Field | Type | Applies to | Description | |---|---|---|---| | `maxConnections` | number? | database | Connection-pool capacity (max concurrent connections). The engine models pool pressure as `activeConnections / maxConnections` (surfaced as `metrics.connection_pressure`); raising it gives the DB more headroom before saturation. Defaults to 100. | | `capacityGB` | number? | storage | Provisioned storage capacity in gigabytes. Used with `maxIops` to model block-storage throughput and IOPS utilization. | | `maxIops` | number? | storage | Provisioned maximum IOPS for a block-storage volume. The engine models IOPS utilization against this ceiling (surfaced as `metrics.storageIopsUtilization`); falls back to the provider's default volume profile IOPS when omitted. | | `cacheHitRate` | number? | cache / CDN | Expected cache hit rate as a fraction between 0 and 1 (e.g. `0.85` = 85%). Higher values reduce load reaching downstream origin/database resources and lower effective latency. Defaults to 0.8 for cache resources. | | `autoscaling` | boolean? | compute | Marks a compute resource as the autoscaling primary. When multiple compute resources exist, the engine targets the one flagged `autoscaling: true`; otherwise it falls back to the first compute resource. | **Simulation Steps** | Method | Path | Auth | Description | |---|---|---|---| | POST | /simulations/{simulationId}/step | Optional | Advance simulation by one time step; applies patterns, capacity model, and autoscaler | | POST | /simulations/{simulationId}/step-hybrid | Bearer (write) | Advance using the Hybrid (rule + ML) Prediction Engine; returns blending metadata | | GET | /simulations/{simulationId}/hybrid-result | Bearer (read) | Retrieve cumulative hybrid decision history and summary statistics | **Step response — metrics fields** Every `/step` response includes a `metrics` object. Optional fields appear only when the relevant resource types are present: | Field | Type | Description | |---|---|---| | `latencyP50` | number | Median response latency (ms) | | `latencyP95` | number | 95th-percentile latency (ms) | | `latencyP99` | number | 99th-percentile latency (ms) | | `cpuUsage` | number | Average CPU utilization across compute resources (%) | | `memoryUsage` | number | Estimated memory utilization (%) | | `throughput` | number | Effective requests per second (goodput after errors) | | `errorRate` | number | Error rate (%) | | `costPerHour` | number | Estimated infrastructure cost (USD/hr) | | `cacheHitRate` | number? | Cache hit rate (%) — only when cache resources exist | | `queueDepth` | number? | Pending messages in queue — only when queue resources exist | | `k8sNodeUtilization` | number? | Kubernetes node CPU utilization (%) — only when k8s resources exist | | `storageIopsUtilization` | number? | OCI Block Volume IOPS utilization (%) — only when OCI block storage exists | | `connectionPressure` | number? | DB connection-pool pressure: `activeConnections / maxConnections`, capped at 3.0. Only present when database resources exist. Values > 1.0 indicate pool exhaustion. Use this to tune agent reward functions based on connection saturation margin. | **Step response — database_overload event metadata** When a `database_overload` failure is active, the generated event includes a `metadata` field with structured connection arithmetic: ```json { "severity": "error", "message": "Database overload: my-db is critically overloaded - connection pool saturated (800 connections)", "resource": "my-db", "metadata": { "activeConnections": 1600, "maxConnections": 800, "connectionUtilizationPct": 200.0 } } ``` `activeConnections` is modelled at 1.2× (minor), 1.5× (moderate), or 2.0× (severe) of `maxConnections`. `connectionUtilizationPct` > 100 means the pool is saturated — values of 150 or 200 indicate the degree of overload. RL agents can use `connectionUtilizationPct` from the event and `connectionPressure` from the step metrics to shape rewards that penalise connection-pool exhaustion. **Traffic & Failure Injection** | Method | Path | Auth | Description | |---|---|---|---| | POST | /simulations/{simulationId}/inject-traffic | x402 \| Bearer (write) | Inject a random 2×–5× traffic spike | | POST | /simulations/{simulationId}/inject-failure | x402 \| Bearer (write) | Kill a random healthy compute node | | GET | /simulations/{simulationId}/patterns | Bearer (read) | List traffic patterns (ramp, burst, step, wave, custom) for the simulation | | POST | /simulations/{simulationId}/patterns | Bearer (write) | Create a new traffic pattern | | PATCH | /patterns/{patternId} | Bearer (write) | Update a traffic pattern | | DELETE | /patterns/{patternId} | Bearer (write) | Delete a traffic pattern | | GET | /simulations/{simulationId}/failures | Bearer (read) | List scheduled failure injections | | POST | /simulations/{simulationId}/failures | Bearer (write) | Schedule a failure injection (instance_kill, az_outage, database_overload, network_latency) | | PATCH | /failures/{failureId} | Bearer (write) | Update a failure injection (e.g. deactivate early) | | DELETE | /failures/{failureId} | Bearer (write) | Delete a failure injection | **POST /simulations/{simulationId}/failures — request body** Create accepts **either a single failure object or a JSON array of failure objects** in one request. Sending an array creates all failure injections at once (handy for setting up a multi-fault chaos scenario in a single call). The response mirrors the request: a single object returns the created failure object (`201`); an array returns an array of created failure objects (`201`), in the same order. Validation is **all-or-nothing**: every element is validated before any is persisted, so if any element is invalid the whole request fails with a `400` and nothing is created. For an array, the offending element's JSON-pointer is prefixed with its index and the message is prefixed with `failures[]: `. For example, if the element at index `2` is missing its required `name`, the error is: ```json { "error": { "code": "MISSING_REQUIRED", "pointer": "/2/name", "message": "failures[2]: Required" } } ``` A single-object request keeps the original error shape (pointers like `/name`, no index prefix). An empty array (`[]`) returns a `400` asking for at least one failure object. ```json [ { "name": "Kill web node", "type": "instance_kill", "startTime": 10, "severity": "severe" }, { "name": "AZ outage us-east-1a", "type": "az_outage", "targetZone": "us-east-1a", "startTime": 20 }, { "name": "DB connection storm", "type": "database_overload", "startTime": 30, "parameters": { "latencyMs": 250 } } ] ``` The `type` must be one of `instance_kill | az_outage | database_overload | network_latency`. `severity` (`minor | moderate | severe`, default `moderate`) and `startTime` (the step the failure begins) apply to all types; `targetResourceId`, `targetZone`, `duration`, `endTime`, and the nested `parameters` object (`latencyMs`, `errorRateIncrease`, `latencyMultiplier`) are optional. `simulationId` is injected by the server; do not include it in the body. **POST /simulations/{simulationId}/patterns — request body** Create accepts **either a single pattern object or a JSON array of pattern objects** in one request. Sending an array creates all patterns at once (handy for multi-phase profiles like ramp → burst → wave). The response mirrors the request: a single object returns the created pattern object (`201`); an array returns an array of created pattern objects (`201`), in the same order. Validation is **all-or-nothing**: every element is validated before any is persisted, so if any element is invalid the whole request fails with a `400` and nothing is created. For an array, the offending element's JSON-pointer is prefixed with its index and the message is prefixed with `patterns[]: `. For example, if the element at index `2` is a ramp missing its target, the error is: ```json { "error": { "code": "MISSING_REQUIRED", "pointer": "/2/parameters/endTraffic", "message": "patterns[2]: A \"ramp\" pattern requires a target traffic level (parameters.endTraffic). ..." } } ``` A single-object request keeps the original error shape (pointers like `/parameters/endTraffic`, no index prefix). An empty array (`[]`) returns a `400` asking for at least one pattern object. ```json [ { "name": "Morning ramp", "type": "ramp", "startTime": 0, "parameters": { "startTraffic": 100, "endTraffic": 500, "duration": 30 } }, { "name": "Lunch burst", "type": "burst", "startTime": 40, "parameters": { "peakTraffic": 5000, "duration": 20 } }, { "name": "Afternoon wave", "type": "wave", "startTime": 70, "parameters": { "baseline": 2000, "amplitude": 800, "period": 120 } } ] ``` The `type` must be one of `ramp | burst | step | wave | custom`. Legacy aliases are accepted and mapped automatically: `spike`→`burst`, `sine`→`wave`, `gradual_increase`→`ramp`. Traffic targets live under a nested `parameters` object (flat top-level fields like `endTraffic` are also accepted and folded into `parameters` for convenience). Each type validates its required fields on create and returns a clear `400` (naming the missing field, with a working example) when one is absent. The pattern moves traffic toward its target — it never adds traffic on top of the live level — so an existing simulation at 100 RPS with a ramp to 500 settles at 500, not a runaway value. ```json { "name": "Morning ramp", "type": "ramp", "startTime": 0, "parameters": { "startTraffic": 100, "endTraffic": 500, "duration": 30 } } ``` | `type` | Required `parameters` | Optional `parameters` (with defaults) | Meaning | |---|---|---|---| | `ramp` (alias `gradual_increase`) | `endTraffic` | `startTraffic` (current traffic), `duration` (60 steps; alias `durationSteps`) | Linearly move traffic to `endTraffic` over `duration` steps | | `step` | `endTraffic` | — | Immediately jump traffic to `endTraffic` | | `burst` (alias `spike`) | `peakTraffic` (alias `burstTraffic`) | `duration` (30 steps; alias `durationSteps`) | Briefly peak traffic at `peakTraffic`, then return to baseline | | `wave` (alias `sine`) | `amplitude` | `baseline` (current traffic; alias `baseTraffic`), `period` (120 steps) | Oscillate traffic around `baseline` by ±`amplitude` every `period` steps | | `custom` | `points` (non-empty array of `{ "time": , "traffic": }`) | — | Linearly interpolate traffic through the supplied points | **Observability** | Method | Path | Auth | Description | |---|---|---|---| | GET | /simulations/{simulationId}/snapshot | Bearer (read) | Single-call run object: architecture + latest metrics + active failures + last 10 significant events + _links. schemaVersion=2. Optional ?since= attaches a diff block (architecture adds/removes/changes, per-metric from/to/delta, failure adds/resolves, recommendation adds/resolves). Returns 404 if pin not found. | | GET | /simulations/{simulationId}/snapshots | Bearer (read) | List pinned snapshot summaries (id, label, pinnedAt, simulationId), newest first. Returns empty array when none pinned. | | GET | /simulations/{simulationId}/snapshots/{pinId} | Bearer (read) | Fetch the full SimulationSnapshot payload (architecture, metrics, failures, events, recommendations) for a specific pinned snapshot. 404 if pin not found. | | POST | /simulations/{simulationId}/snapshots | Bearer (write) | Pin the current simulation state; returns { pinnedSnapshotId, pinnedAt, label, simulationId }. Up to 20 pins retained per simulation. Pass pinnedSnapshotId as ?since= to GET /snapshot for a diff. | | GET | /simulations/{simulationId}/metrics | Bearer (read) | Full time-series metrics history (CPU, latency percentiles, error rate, throughput, cost/hr, connectionPressure) | | GET | /simulations/{simulationId}/events | Bearer (read) | Chronological event log (autoscaling, failures, cost spikes, manual annotations) | | POST | /simulations/{simulationId}/events | Bearer (write) | Manually inject an event annotation into the log | | DELETE | /simulations/{simulationId}/events | Bearer (write) | Clear all events from the simulation event log | **POST /simulations/{simulationId}/events — request body** ```json { "severity": "info", "message": "Deploying v2.3.1 — watching for latency regression", "resource": "web-tier" } ``` Required fields: `severity` (`"info"`, `"success"`, `"warning"`, or `"error"`) and `message` (free-text annotation string). `resource` is optional and names the affected resource. `simulationId` is injected by the server; do not include it in the body. The response (`201 Created`) returns the stored event object: `{ id, simulationId, timestamp, severity, message, resource? }`. **DELETE /simulations/{simulationId}/events** returns `204 No Content` with an empty body. All events are permanently removed from the simulation event log. **AI Analysis** | Method | Path | Auth | Description | |---|---|---|---| | POST | /simulations/{simulationId}/explain | Bearer (write) or x402 (`ai_explain`, $0.0010) | GPT-5: natural-language explanation of current simulation behaviour | | POST | /simulations/{simulationId}/optimize | Bearer (write) or x402 (`ai_optimize`, $0.0010) | GPT-5: prioritised infrastructure optimisation suggestions | | POST | /simulations/{simulationId}/troubleshoot | Bearer (write) or x402 (`ai_troubleshoot`, $0.0010) | GPT-5: step-by-step troubleshooting for a user-described issue | | POST | /simulations/{simulationId}/analyze-bottlenecks | Bearer (write) or x402 (`ai_bottleneck`, $0.0010) | GPT-5: identify performance bottlenecks and DigitalOcean migration recommendations | | POST | /simulations/{simulationId}/explain-autoscaling | Optional | GPT-5: explain why autoscaling actions were or were not taken | **Right-Sizing & Accuracy** | Method | Path | Auth | Description | |---|---|---|---| | POST | /simulations/{simulationId}/bulk-resize | Bearer (write) or x402 (`bulk_resize`, $0.0010) | Resize all compute resources to a specified DigitalOcean Droplet size slug | | GET | /simulations/{simulationId}/right-sizing-hint | Bearer (read) or x402 (`right_sizing_hint`, $0.0010) | Recommend smaller resource sizes for over-provisioned nodes (with savings %) | | GET | /simulations/{simulationId}/validate-cost-accuracy | Bearer (read) or x402 (`validate_cost_accuracy`, $0.0010) | Validate simulated cost/hr is within ±10% of provider benchmark. Agent contract: only trust `valid` when `checked: true`; `checked: false` means no benchmark reference matched and `valid: true` is a vacuous truth. | | GET | /simulations/{simulationId}/validate-performance-accuracy | Bearer (read) or x402 (`validate_performance_accuracy`, $0.0010) | Validate simulated throughput/latency is within ±15% of provider benchmark. Agent contract: only trust `valid` when `checked: true`; `checked: false` means no benchmark reference matched and `valid: true` is a vacuous truth. | | GET | /simulations/{simulationId}/validate-accuracy | Bearer (read) or x402 (`validate_accuracy`, $0.0010) | Combined cost + performance accuracy check; returns `overallValid` flag. Agent contract: only trust `overallValid` when `checked: true`; `checked: false` means nothing was compared. | **Accuracy validator response fields — `skippedCount` and `skippedReasons`** All three accuracy validators (`validate-cost-accuracy`, `validate-performance-accuracy`, `validate-accuracy`) include two fields that explain which resources were excluded from the check: | Field | Type | Description | |---|---|---| | `skippedCount` | integer | Number of resources (or resource-metric pairs) that were evaluated but had no matching benchmark entry and were therefore skipped. A non-zero value means the `valid` / `overallValid` verdict covers only the resources that were checked — not the full set. | | `skippedReasons` | string[] | Human-readable explanation for each skipped resource. Common reasons: no `serviceFamily` set, or no pricing benchmark found for the provider/serviceFamily/size combination. Example: `['"cache-layer": no serviceFamily set']`. | Agent contract: always inspect `skippedCount` alongside `checked` — `checked: true` with `skippedCount > 0` means the verdict is valid but partial (some resources were compared; others were not). `checked: false` with `skippedCount > 0` means every resource was skipped and nothing was compared. ### Scenarios API Pre-built infrastructure scenario templates. No authentication required. | Method | Path | Auth | Description | |---|---|---|---| | GET | /scenarios | Public | List all scenario templates (name, category, provider, resources) | | GET | /scenarios/{scenarioId} | Public | Get full details of a single scenario template including connections | ### Simulation Fidelity API Exposes the benchmark sources and accuracy thresholds used to calibrate the simulation engine. No authentication required. | Method | Path | Auth | Description | |---|---|---|---| | GET | /fidelity | Public | Per-provider benchmark data (pricing and performance) and accuracy thresholds (cost ±10%, performance ±15%) | | GET | /accuracy-benchmark | Public | Run the deterministic accuracy benchmark against the canonical AWS architecture (ALB → 2× m5.large EC2 → db.r5.large RDS MySQL); returns per-scenario simulated vs. reference metrics and composite accuracy scores | | POST | /accuracy-benchmark | Public | Run the accuracy benchmark with a custom provider, compute type, and database type; supports `aws`, `gcp`, `azure`, `oci`, and `digitalocean`; see request body details below | **POST /accuracy-benchmark — request body** Required fields: `provider` (`"aws"`, `"gcp"`, `"azure"`, `"oci"`, or `"digitalocean"`), `computeCount` (integer, 1–10), `computeType` (provider-specific string), `dbType` (provider-specific string). Valid values by provider: | provider | computeType | dbType | |---|---|---| | `aws` | `t2.micro`, `m5.large`, `m5.xlarge` | `db.t3.small`, `db.r5.large` | | `gcp` | `e2-medium`, `n2-standard-4` | `db-f1-micro`, `db-n1-standard-2` | | `azure` | `Standard_B2s`, `Standard_D4s_v3` | `sql-basic`, `sql-s2` | | `oci` | `VM.Standard.E4.Flex`, `VM.Standard3.Flex` | `mysql-heatwave`, `autonomous-db-std` | | `digitalocean` | `s-2vcpu-4gb`, `c-4` | `db-s-1vcpu-1gb`, `db-s-2vcpu-4gb` | **AWS example** (canonical architecture, 2× m5.large + db.r5.large): ```json { "provider": "aws", "computeCount": 2, "computeType": "m5.large", "dbType": "db.r5.large" } ``` **GCP example** (2× n2-standard-4 Compute Engine + Cloud SQL db-n1-standard-2): ```json { "provider": "gcp", "computeCount": 2, "computeType": "n2-standard-4", "dbType": "db-n1-standard-2" } ``` **Azure example** (2× Standard_D4s_v3 VM + Azure SQL Standard S2): ```json { "provider": "azure", "computeCount": 2, "computeType": "Standard_D4s_v3", "dbType": "sql-s2" } ``` **OCI example** (2× VM.Standard3.Flex + MySQL HeatWave): ```json { "provider": "oci", "computeCount": 2, "computeType": "VM.Standard3.Flex", "dbType": "mysql-heatwave" } ``` **DigitalOcean example** (2× s-2vcpu-4gb Droplet + Managed Database db-s-2vcpu-4gb): ```json { "provider": "digitalocean", "computeCount": 2, "computeType": "s-2vcpu-4gb", "dbType": "db-s-2vcpu-4gb" } ``` The response shape is identical to `GET /accuracy-benchmark` (same four scenarios, same metrics, same composite score structure) plus `"isCustomConfig": true`. The fixed seed `20240601` is always used so results are reproducible. **Per-provider accuracy score driver notes** The `scoreDriverNote` field is returned in every `GET /accuracy-benchmark` and `POST /accuracy-benchmark` response. It explains why a provider's composite accuracy score diverges from the AWS reference baseline. These notes are also shown as tooltips in the "All Providers at a Glance" comparison table in the simulation UI. ```json [ { "provider": "aws", "scoreDriverNote": "AWS m5.large EC2 + db.r5.large RDS — latency, tail, CPU and error coefficients are all least-squares-fit to AWS's documented reference scenarios, the same method used for every other provider. The residual gap is real CloudWatch measurement noise in the references (mainly the P95 tail) that a smooth curve cannot track perfectly." }, { "provider": "gcp", "scoreDriverNote": "GCP uses its own latency and error coefficients fit to e2-standard-2 / db-n1-standard-2 reference data, plus a +5 ms idle base-latency offset (Cloud LB forwarding over AWS ALB) so idle P50 reproduces the documented floor. Latency, error rate (including Burst) and low/mid-load CPU track references closely; the main remaining gap is the shared (AWS-calibrated) database CPU curve, which slightly over-predicts CPU at Burst." }, { "provider": "azure", "scoreDriverNote": "Azure uses its own latency and error coefficients fit to Standard_D2s_v3 / SQL Standard S2 reference data, plus a +3.75 ms idle base-latency offset so idle P50 reproduces the documented floor. Latency and error rate (including Burst) track references closely; the largest remaining divergence is at Burst, where the shared (AWS-calibrated) database CPU saturation curve over-predicts CPU for the 200-connection S2 tier." }, { "provider": "oci", "scoreDriverNote": "OCI uses its own latency, error, CPU, tail and throughput-shed coefficients fit to VM.Standard.E4.Flex 2-OCPU / MySQL HeatWave reference data, plus a +6.25 ms idle base-latency offset (EPYC + Flexible LB overhead) so idle P50 reproduces the documented floor. HeatWave's low in-memory error rates are captured by the fitted polynomial (Burst error matches closely), and a connection-pool goodput-shed term reproduces the documented Peak/Burst effective throughput (which sits below traffic × (1 − errorRate) due to admission back-pressure). The residual is in CPU: OCI's reference curve is unusually steep (low Normal 12 % yet high Burst 78 %), which the shared √-shaped compute curve plus the shared database CPU curve cannot fully track — leaving CPU slightly over-predicted at Normal and under-predicted at Peak/Burst." }, { "provider": "digitalocean", "scoreDriverNote": "DigitalOcean uses its own latency and error coefficients fit to s-4vcpu-8gb / db-s-2vcpu-4gb reference data, plus a +9 ms idle base-latency offset (shared-tenant network fabric) so idle P50 reproduces the documented floor. Latency and CPU track references across all tiers; the main remaining divergence is the very low documented error rates at Idle/Normal, where sub-0.5 % absolute references make small noise-floor differences a large relative delta." } ] ``` #### Fidelity notes — request-based and serverless resources Several AWS resources use a billing unit that cannot be directly expressed as a flat hourly instance rate. These resources are **excluded from the FR-12 ±10% cost-accuracy check** and instead use a flat simulation approximation that represents a moderate reference workload. **Aurora Serverless v2 (`aurora-serverless`) — ACU-based cost model** Aurora Serverless v2 bills per ACU-hour ($0.12/ACU-hr in us-east-1, May 2026). The ACU count is not fixed: the engine scales it continuously between `minCapacity` and `maxCapacity` in response to actual database load. Because the simulation cannot know the instantaneous ACU count without running a full database load model, the simulated hourly cost is approximated as a **flat $0.12/hr** (equivalent to 1 ACU held constant). This approximation is accurate for lightly loaded or idle workloads; at sustained high load the actual cost may exceed the simulation estimate. Cost comparison to provisioned Aurora: | Resource | Billing model | Simulated cost | Official rate | Notes | |---|---|---|---|---| | Aurora Serverless v2 | $0.12/ACU-hr, scales with load | $0.12/hr (flat, 1 ACU reference) | $0.12/ACU-hr | Excluded from FR-12; approximation holds at ≤1 ACU sustained load | | Aurora PostgreSQL (db.r6g.large) | Fixed hourly instance rate | $0.26/hr | $0.26/hr | Within FR-12 ±10% accuracy bound | At 1 ACU the Aurora Serverless v2 cost is roughly half the provisioned `aurora-postgresql` (db.r6g.large) cost. The breakeven point — where ACU-based billing matches the provisioned instance cost — is approximately **2.2 ACUs** ($0.12 × 2.2 ≈ $0.26/hr). Workloads that sustain more than ~2.2 ACUs are cheaper on a provisioned instance; workloads that spend significant time below 2.2 ACUs (or auto-pause) are cheaper on Aurora Serverless v2. The simulation's flat $0.12/hr approximation reflects the lower end of this range and is intentionally conservative (under-estimating cost for high-ACU workloads). Because Aurora Serverless v2 is excluded from FR-12, the `/simulations/{id}/validate-cost-accuracy` and `/simulations/{id}/validate-accuracy` endpoints skip it when computing the overall cost accuracy verdict. Agents relying on cost comparisons between `aurora-serverless` and `aurora-postgresql` variants should treat the serverless cost figure as a lower-bound estimate. **Aurora DSQL (`aurora-dsql`) — DPU-second + request-unit cost model** Aurora DSQL bills on two dimensions simultaneously: compute time measured in DPU-seconds ($0.000463/DPU-second in us-east-1, May 2026) and per-operation request units charged separately for reads and writes. Because the simulation has no visibility into either the instantaneous DPU count or the request-unit volume generated by a workload, neither dimension can be computed accurately from the simulation state alone. The simulated hourly cost is therefore approximated as a **flat $0.12/hr**, representing a lightly loaded reference workload. At higher DPU counts or elevated read/write throughput the actual cost will exceed this estimate. Cost comparison to provisioned Aurora: | Resource | Billing model | Simulated cost | Official rate | Notes | |---|---|---|---|---| | Aurora DSQL | DPU-second + read/write request units | $0.12/hr (flat reference) | $0.000463/DPU-second + request units | Excluded from FR-12; approximation reflects low-load baseline only | | Aurora Serverless v2 | $0.12/ACU-hr, scales with load | $0.12/hr (flat, 1 ACU reference) | $0.12/ACU-hr | Excluded from FR-12; approximation holds at ≤1 ACU sustained load | | Aurora PostgreSQL (db.r6g.large) | Fixed hourly instance rate | $0.26/hr | $0.26/hr | Within FR-12 ±10% accuracy bound | Aurora DSQL's flat $0.12/hr simulation approximation matches the Aurora Serverless v2 approximation at the 1-ACU reference point, but the two resources have fundamentally different scaling characteristics. Aurora DSQL is a distributed, serverless relational database designed for high availability across regions; its DPU consumption rises with query concurrency and data volume in ways that are decoupled from the simulation's compute-instance model. Agents comparing `aurora-dsql` and `aurora-postgresql` costs should treat the DSQL figure as a floor — a lower-bound estimate valid only for very low-throughput workloads. Because Aurora DSQL is excluded from FR-12, the `/simulations/{id}/validate-cost-accuracy` and `/simulations/{id}/validate-accuracy` endpoints skip it when computing the overall cost accuracy verdict. Agents building cost-optimization strategies that include Aurora DSQL alongside `aurora-serverless` and `aurora-postgresql` should account for the fact that all three resources carry different uncertainty levels: `aurora-postgresql` is within ±10%, `aurora-serverless` is a lower-bound ACU estimate, and `aurora-dsql` is a lower-bound DPU+request estimate. ### Pricing History API Historical and current cloud provider pricing data. No authentication required. | Method | Path | Auth | Description | |---|---|---|---| | GET | /pricing-history | Public | Pricing history document: snapshots, recent changes, per-provider trends, and resource ID list | | GET | /pricing-history/trend/{resourceId} | Public | Full price time-series for a specific resource type (use GET /pricing-history to discover valid resource IDs) | | GET | /admin/pricing-check-status | Public | Latest automated pricing-drift check status: maps each check identifier (e.g. aws-ec2-m5large) to pass/drift/error, with the timestamp of the last run | ### RL Training API Train reinforcement learning agents on the autoscaling simulator. Supports episode lifecycle management, multi-objective reward functions (cost, latency, availability), and provider-specific autoscaling behavior (warm-up latency, cooldown periods, scaling dynamics). | Method | Path | Auth | Description | |---|---|---|---| | POST | /rl/environments | Bearer | Create a new RL environment linked to a simulation | | GET | /rl/environments/{environmentId} | Bearer | Get environment state and current configuration | | GET | /rl/environments/{environmentId}/observation | Bearer | Get the latest observation; returns `{obs, metrics}` where obs has decision features (rps, cpu_util, instances, traffic, currentTime, tick_seconds) and metrics has evaluation outputs (cost_usd_hr, latency_p95, error_rate, uptime, sla_violations, connection_pressure?, serverless?) | | POST | /rl/environments/{environmentId}/batch-step | Bearer / x402 | Execute up to 30 actions in one HTTP round-trip; each action counts as 1 call against the 5 000 req/hr RL quota; stops early if episode ends; returns `{results: StepResponse[]}`. On 429 read the `Retry-After` response header (seconds until reset) and back off before retrying. | | POST | /rl/environments/{environmentId}/eval-episodes | Bearer / x402 | Submit an eval-episode job (async by default). Returns `202 Accepted` immediately with `{jobId, status, createdAt}`; poll `GET /rl/environments/{environmentId}/eval-episodes/{jobId}` until `status` is `completed` or `failed`. Use `?sync=true` to run inline and get the full result directly with `200 OK`. The result shape is `{episodes, meanEvalReward, trainingTotalReward, collapseThreshold, reward_collapse}` where `reward_collapse` flags policies that exploit unpriced cost dimensions. | | GET | /rl/environments/{environmentId}/eval-episodes/{jobId} | Bearer | Retrieve the result of an async eval-episode job. Returns `202` with `{jobId, status, createdAt}` while pending or running; returns `200` with the full result merged with job metadata when `status` is `completed`; returns `200` with `{jobId, status, error, createdAt, completedAt}` when `status` is `failed`. | | POST | /rl/environments/{environmentId}/reset | Bearer | Reset environment to initial state for a new episode | | POST | /rl/environments/{environmentId}/step | Bearer | Execute an action; returns `{t, obs, metrics, reward (scalar), reward_components, done, info}` — obs and metrics use same shape as the observation endpoint | **Observation space (`obs`)**: rps (req/s), cpu_util (0-1 fraction), instances (compute count), traffic, currentTime, tick_seconds (simulation seconds per step), unmodeled_dimensions_active (boolean — true when evalCostOverrides are active; signals an eval episode to the policy), warmup_factor (optional 0-1 capacity factor — 1.0 when all compute instances are fully warmed; below 1.0 while any instance is still in its JIT warm-up window; absent when no resources carry a warm-up counter). **Evaluation metrics (`metrics`)**: cost_usd_hr, latency_p95 (ms), error_rate (0-1), uptime (0-1), sla_violations, connection_pressure (DB pool ratio). The connection_pressure metric is optional and only present when the simulation contains database resources — it is the activeConnections / maxConnections ratio capped at 3.0; values above 1.0 indicate pool exhaustion; use it to build DB-aware reward functions. The optional `serverless` array gives a **per-DB breakdown** for each Aurora Serverless v2 database in the simulation (one entry per serverless DB; omitted entirely when none exist) — each entry has `resourceId`, `name`, `cpu_util` (0-1 fraction), `acu`, `min_acu`, `max_acu`, `warming` (true during the ~4-step ACU warm-up window when this DB's cpu_util is 0), `cost_usd_hr` (this DB's own ACU-proportional cost, ~$0.06/hr at the 0.5-ACU floor), and `connection_pressure` (this DB's own pool ratio against its ACU-scaled pool, ~200 connections per ACU). Use it because the sim-wide `cpu_util` and `cost_usd_hr` aggregates average across all resources and mask a single serverless DB's cpu=0 warming window and ACU-floor cost, and the sim-wide `connection_pressure` dilutes one DB's pool saturation across every database. The optional `databases` array gives a **per-DB summary** for every database resource in the simulation (one entry per database; omitted when none exist) — each entry has `resource_id`, `name`, `cpu_util` (0-1 fraction), `max_connections`, `connection_pressure` (pool ratio), and `is_serverless` (boolean). Unlike `serverless`, which is Aurora Serverless v2-only and includes ACU fields, `databases` covers all database types including provisioned RDS, Cloud SQL, and Azure SQL. Use `databases` when you need a uniform per-DB view across a mixed-engine topology. **Per-resource recovery policy in observations**: Every resource object in the `resources` array of the observation (returned by both the observation endpoint and step responses) includes a `recoveryPolicy` field with four fields: `criticalCpuThreshold` (default 80), `criticalSteps` (default 4), `warningCpuThreshold` (default 70), `warningSteps` (default 3). Resources that have never had `set_recovery_policy` applied will carry the global defaults. Agents can read `observation.resources[i].recoveryPolicy` to compare healing configurations across resources, confirm a `set_recovery_policy` action took effect, or detect policy drift between resources serving similar roles. **Action types**: `scale_out`, `scale_in`, `adjust_threshold`, `add_resource`, `remove_resource`, `no_op`, `set_recovery_policy`. | Action | Parameters | Description | |---|---|---| | `scale_out` | `instanceCount` (int) or `instances` (int alias) | Add compute instances to increase capacity | | `scale_in` | `instanceCount` (int) or `instances` (int alias) | Remove compute instances to reduce cost | | `adjust_threshold` | `cpuThreshold` (0–100) | Change the autoscaling CPU trigger threshold | | `add_resource` | `resourceType`, `provider`, `serviceFamily`, `config` | Provision a new resource (compute or database) into the running simulation | | `remove_resource` | `resourceId` (string) | Remove an existing resource from the simulation | | `no_op` | *(none)* | Advance the simulation clock by one tick (or `tick_seconds`) without triggering any resource change. Recommended during the aurora-serverless ACU ramp window (steps 1–4) when `obs.cpu_util` reads `0` and no autoscaling decision is warranted. | | `set_recovery_policy` | `resourceId` (string), `recoveryPolicy` (object) | Override the recovery thresholds for a specific resource. `recoveryPolicy` fields: `criticalCpuThreshold` (0–100, default 80), `criticalSteps` (int ≥ 1, default 4), `warningCpuThreshold` (0–100, default 70), `warningSteps` (int ≥ 1, default 3). Use this to vary how quickly individual resources heal — stateless workloads benefit from aggressive (low step count) recovery; stateful workloads may need conservative (high step count) thresholds to avoid flapping. **Policies set via this action are persisted in the environment row and automatically re-applied on every subsequent `/reset` call — agents do not need to re-apply them after each episode.** | **Action parameter note — `instanceCount` vs `obs.instances`**: The `instanceCount` parameter in `scale_out` and `scale_in` actions is the number of instances to add or remove (delta, not a target). The `obs.instances` field in every observation is a read-only state count — the total number of active compute instances at that step — and is not an action parameter. **Per-resource instance bounds**: A compute resource's `characteristics.maxInstances` and `characteristics.minInstances` act as hard per-resource ceilings/floors for `scale_out` and `scale_in` actions. The effective maximum is `min(autoscalingConfig.maxInstances, characteristics.maxInstances)` and the effective minimum is `max(autoscalingConfig.minInstances, characteristics.minInstances)`. When an action is trimmed to honour these bounds, the step response `info` object gains four flat keys: `scale_clamped: true` (boolean), `requested` (integer — the `instanceCount` delta the agent requested), `actual` (integer — the delta actually applied; `0` if the action was fully blocked because the fleet is already at the limit), and `limit` (integer — the effective bound that triggered clamping). These keys are absent when no clamping occurred. **RL traffic source**: Traffic in RL episodes is driven by the environment's `episodeConfig`, not by simulation `/patterns` endpoints. Patterns created on the underlying simulation (via `POST /simulations/{id}/patterns`) are not applied to RL episodes — they only affect the workspace UI simulation. To drive high-RPS load in an episode, set `episodeConfig.initialTraffic` (e.g. `"initialTraffic": 50000`) when creating or resetting the environment, or use `add_resource` with a traffic-intensive configuration. The `episodeConfig.targetTrafficPattern` field (`ramp`, `burst`, `step`, `wave`, `custom`) controls how traffic evolves during the episode independently of any sim-level patterns. **`add_resource` action — AWS database `serviceFamily` values**: Use these in the `resource.serviceFamily` field when the action type is `add_resource` and `resource.type` is `"database"` with `resource.provider` `"aws"`: | serviceFamily | Description | |---|---| | `aurora-postgresql` | Provisioned Aurora PostgreSQL cluster — fixed instance size, predictable cost | | `aurora-dsql` | Aurora DSQL — distributed serverless SQL optimized for high-concurrency, multi-region writes | | `aurora-serverless` | Aurora Serverless v2 — scales ACUs continuously between `minCapacity` and `maxCapacity`; cost tracks actual load rather than peak provisioned size; best choice when workload is variable or unpredictable | **Cost is auto-derived from shape — you do not need to send `costMultiplier`**: When you create a resource via the API (`POST /simulations`), the `add_resource` action, or any agent/RL path, the simulation derives the correct hourly cost from the resource's `serviceFamily` + `size` (instance class) using the same pricing benchmark that powers the accuracy page and the `validate-cost-accuracy` endpoint. The minimal characteristics for a correctly-priced AWS database are just `serviceFamily` + `size` — for example `{ "serviceFamily": "aurora-postgresql", "size": "db.r6g.large" }` prices at ≈ $0.26/hr and `{ "serviceFamily": "rds", "size": "db.r5.large" }` prices at ≈ $0.24/hr, with no `costMultiplier` supplied. Set `costMultiplier` explicitly only to override the derived rate for advanced/what-if pricing; an explicit non-default value is always honored. Request-based / FR-12-excluded shapes (`aurora-serverless`, `aurora-dsql`, DynamoDB, Lambda) have no per-shape benchmark and keep their documented flat lower-bound approximation regardless of `size`. **RL quickstart — Aurora Serverless v2 as a cost-optimizing `add_resource` action**: ```json { "action": "add_resource", "resource": { "name": "aurora-sv2", "type": "database", "provider": "aws", "serviceFamily": "aurora-serverless", "config": { "minCapacity": 0.5, "maxCapacity": 16 } } } ``` Use this action when the agent detects high `cost_usd_hr` and low sustained `cpu_util`, or when it wants to trial a database tier that scales to near-zero ACUs during idle periods. `minCapacity` (ACUs) sets the floor; `maxCapacity` sets the ceiling. Reward signal will reflect the lower per-step cost once the simulated workload drops below the provisioned-instance breakeven point. **Aurora Serverless v2 — expected observation shape after `add_resource`**: The simulation models a **2–4 step ACU scale-out delay** before the resource reaches operating capacity. During this ramp period `cpu_util` for the new resource reads `0` and `cost_usd_hr` reflects only the `minCapacity` ACU floor (≈ $0.06/hr at 0.5 ACUs in us-east-1). Once the simulated workload is routed to the resource, ACUs scale proportionally to load; the engine advances ACUs in discrete increments per step, so `cost_usd_hr` rises incrementally over **3–6 steps** rather than jumping immediately to the steady-state value. At steady state, `cpu_util` stabilises in the **20–70 %** range for typical OLTP workloads, `latency_ms` falls relative to a saturated provisioned Aurora instance, and `cost_usd_hr` settles between the floor cost and the full `maxCapacity` rate (≈ $1.92/hr at 16 ACUs). When load drops below the `minCapacity` breakeven, `cpu_util` returns to near `0` and `cost_usd_hr` reverts to the floor within **1–2 steps**. Tune reward functions to account for the ramp lag: penalise latency violations during the first 4 steps after the action rather than treating them as a steady-state failure. **Aurora Serverless v2 — episode-loop quickstart (Python)**: ```python import requests BASE = "https://www.cloudworldmodel.ai/api" HEADERS = {"Authorization": "Bearer ", "Content-Type": "application/json"} # 1. Create an RL environment linked to an existing simulation that already contains # at least one AWS database resource (the engine clones it for the new step). env = requests.post(f"{BASE}/rl/environments", json={"simulationId": "", "episodeConfig": {"maxSteps": 40, "tick_seconds": 60}}, headers=HEADERS).json() env_id = env["environment"]["id"] # 2. add_resource action — adds an AWS database resource to the running simulation. # The engine models a 2–4 step ACU scale-out delay for aurora-serverless targets. # Step request shape: {"action": {"type": "...", "parameters": {...}}, "tick_seconds": N} step1 = requests.post(f"{BASE}/rl/environments/{env_id}/step", headers=HEADERS, json={ "action": { "type": "add_resource", "parameters": {"resourceType": "database", "provider": "aws"} }, "tick_seconds": 60 }).json() # Step response keys: t, obs, metrics, reward, reward_components, done t = step1["t"] # step index (1 after first action) obs = step1["obs"] # {rps, cpu_util, instances, traffic, currentTime, tick_seconds} metrics = step1["metrics"] # {cost_usd_hr, latency_p95, error_rate, uptime, sla_violations} # 3. Ramp window (t = 1–4): obs.cpu_util == 0, metrics.cost_usd_hr at minCapacity floor (~$0.06/hr). # Use no_op to advance the clock without making any autoscaling decision (see Action types table). # Only count cost + stability reward components — skip performance and sla during ACU ramp-up. RAMP_STEPS = 4 result = step1 for _ in range(RAMP_STEPS): result = requests.post(f"{BASE}/rl/environments/{env_id}/step", headers=HEADERS, json={ "action": {"type": "no_op", "parameters": {}}, "tick_seconds": 60 }).json() t = result["t"] obs = result["obs"] metrics = result["metrics"] rc = result["reward_components"] # Exclude performance and sla components during ACU ramp to avoid false latency penalties adjusted_reward = rc["cost"] + rc["stability"] print(f"Ramp t={t:2d} cpu_util={obs['cpu_util']:.3f} " f"cost_usd_hr={metrics['cost_usd_hr']:.4f} adj_reward={adjusted_reward:.3f}") # 4. Steady-state training (t >= 5): all reward components are now meaningful. With a database # resource present this is five components — performance, cost, stability, sla, and the # connection_pressure DB-pool penalty (see the worked connection-pool example below). # metrics.cost_usd_hr climbs over 3–6 steps toward the ACU-proportional steady-state rate. done = result["done"] while not done: result = requests.post(f"{BASE}/rl/environments/{env_id}/step", headers=HEADERS, json={ "action": {"type": "adjust_threshold", "parameters": {"cpuThreshold": 70}}, "tick_seconds": 60 }).json() t = result["t"] obs = result["obs"] metrics = result["metrics"] reward = result["reward"] done = result["done"] print(f"Train t={t:2d} cpu_util={obs['cpu_util']:.3f} " f"latency_p95={metrics['latency_p95']:.0f}ms " f"cost_usd_hr={metrics['cost_usd_hr']:.4f} reward={reward:.3f}") # 5. Reset for the next episode requests.post(f"{BASE}/rl/environments/{env_id}/reset", headers=HEADERS) ``` Key points: - **Step request shape**: `{ "action": { "type": "", "parameters": {...} }, "tick_seconds": 60 }`. - **Step response keys**: `t` (step index), `obs` (rps, cpu_util, instances, traffic, currentTime, tick_seconds), `metrics` (cost_usd_hr, latency_p95, error_rate, uptime, sla_violations, connection_pressure?, serverless?), `reward`, `reward_components` (performance, cost, stability, sla, connection_pressure?), `done`. - **Ramp window (t = 1–4)**: `obs.cpu_util` is `0`; `metrics.cost_usd_hr` holds at the `minCapacity` floor (~$0.06/hr at 0.5 ACUs). Exclude `reward_components.performance` and `reward_components.sla` to avoid penalising latency noise during ACU scale-out. - **Steady state (t ≥ 5)**: all reward components are meaningful — performance, cost, stability, sla, plus `connection_pressure` when the simulation contains a database resource (five signals in that case); `metrics.cost_usd_hr` settles between the floor and the full `maxCapacity` rate (~$1.92/hr at 16 ACUs) proportional to actual OLTP load. - Use `tick_seconds=60` for fine-grained training; use `tick_seconds=300` for warm-up fast-forward (see tick-rate notes below). **Reward components (`reward_components`)**: performance (latency adherence), cost (cost efficiency), stability (autoscaling stability penalty), sla (SLA violation penalty), unmodeled_cost (extra penalty from evalCostOverrides — egress/cross_az_traffic surcharges applied only inside eval episodes; absent in normal training; reveals blind spots when eval reward drops vs training reward), connection_pressure (DB pool saturation penalty — only present when database resources exist; 0 when pool pressure ≤ 1.0, decreases with slope −1 per unit from 1.0 to 1.5 reaching −0.5, then drops with slope −2 per unit above 1.5 — twice as steep — flooring at −1.0 at pressure ≥ 1.75; added directly to the weighted sum so agents learn to scale databases before pool exhaustion. **Important — multi-DB topologies:** `reward_components.connection_pressure` uses the **worst-case (highest) per-DB connection pressure** across all databases, not the sim-wide aggregate. In a primary + replica topology the aggregate dilutes the primary's saturation (e.g. a primary at CP 3.0 with a replica at CP 0.25 gives an aggregate of ~0.476, below the 1.0 threshold). Using the max ensures the agent receives a meaningful penalty even when a healthy replica masks a saturated primary. `metrics.connection_pressure` in the `metrics` block is still the sim-wide aggregate — use `metrics.databases[].connection_pressure` for the full per-DB breakdown. This component is absent until a database resource first exists; when you add a DB mid-episode via add_resource, the penalty is ramped in linearly over 5 steps — starting at 1/5 of its full magnitude on the first step it appears and reaching full strength after 5 steps — so the introduction does not cause a sudden step-to-step reward discontinuity that would look like noise to your agent. Treat the first appearance as a near-zero baseline). **Reward weights (`rewardWeights`)**: Set at create or reset time to control how each reward component contributes to the scalar total. Valid create-time keys: `cost` (cost optimization), `resilience` (low error rates and SLA compliance), `latency` (low P95 latency), `performance` (throughput and capacity), `stability` (autoscaling stability, penalizes thrashing). These are distinct from the step-response `reward_components` fields (`connection_pressure`, `unmodeled_cost`, `sla`) which are computed automatically and not user-weighted. Values are normalized server-side to sum to 1.0 — send raw priority scores or pre-normalized fractions. Example: `{ "cost": 0.4, "resilience": 0.2, "latency": 0.2, "performance": 0.1, "stability": 0.1 }`. When omitted the built-in default weighting applies (latency 0.35 / resilience 0.40 / cost 0.25). **batch-step vs eval-episodes request body**: These two multi-action endpoints use different body schemas. `POST .../batch-step` uses a `steps` array — each element is `{"action": {...}, "tick_seconds": N}` — and executes actions sequentially in the live environment. `POST .../eval-episodes` uses an `actions` 2-D array — each outer element is one episode (an ordered list of `Action` objects) — and runs ephemeral rollouts without mutating the stored environment state. Example eval-episodes request body: `{"actions": [[{"type": "no_op", "parameters": {}}, {"type": "scale_out", "parameters": {"instanceCount": 1}}]], "collapseThreshold": 0.20}`. **Worked example — the connection-pool penalty when a database is overloaded**: When the simulation contains a database resource, every step also reports `metrics.connection_pressure` (the `activeConnections / maxConnections` ratio, capped at 3.0) and adds the fifth `reward_components.connection_pressure` signal. As traffic climbs past what the database's pool can absorb, the ratio crosses 1.0 and the penalty turns negative. For example, after the agent lets RPS rise without scaling the database, a step might return: ```json { "t": 12, "obs": { "rps": 1800, "cpu_util": 0.74, "instances": 3, "traffic": 1800, "currentTime": 720, "tick_seconds": 60 }, "metrics": { "cost_usd_hr": 0.42, "latency_p95": 240, "error_rate": 0.02, "uptime": 0.998, "sla_violations": 0, "connection_pressure": 1.3 }, "reward": -0.18, "reward_components": { "performance": 0.12, "cost": -0.05, "stability": 0.05, "sla": 0.0, "connection_pressure": -0.3 }, "done": false } ``` Here `metrics.connection_pressure` is `1.3` (the pool is at 130% of capacity), so `reward_components.connection_pressure` is `-0.3` — on the slope −1 segment, `-(1.3 − 1.0) = −0.3`. That penalty is added straight onto the weighted base reward, dragging the total `reward` negative even though `performance` is still positive. The lesson for an agent: when `metrics.connection_pressure` approaches 1.0, act on the **database** (scale it up for a higher `maxConnections`, add read replicas to spread connections, add a cache to cut query volume, or use a connection pooler) rather than only scaling the compute tier — scaling web instances alone does not relieve pool saturation and the `connection_pressure` penalty will keep growing (steeper above 1.5, flooring at −1.0 by pressure ≥ 1.75). **Worked example — the per-DB `serverless` breakdown in a multi-resource simulation**: When the simulation mixes a busy compute tier with an Aurora Serverless v2 database, the sim-wide `metrics.cpu_util` and `metrics.cost_usd_hr` are aggregates that average across every resource, so a single serverless DB sitting in its cpu=0 warm-up window or pinned at the ~$0.06/hr ACU floor is invisible at the top level, and the sim-wide `connection_pressure` spreads one DB's pool saturation across all databases. The optional `metrics.serverless` array exposes each serverless DB on its own. For example, while the compute tier is saturated during the warm-up window a step might return: ```json { "t": 3, "obs": { "rps": 5000, "cpu_util": 0.95, "instances": 2, "traffic": 5000, "currentTime": 180, "tick_seconds": 60 }, "metrics": { "cost_usd_hr": 0.21, "latency_p95": 180, "error_rate": 0.01, "uptime": 0.999, "sla_violations": 0, "connection_pressure": 0.8, "serverless": [ { "resource_id": "aurora-sl", "name": "Aurora Serverless DB", "cpu_util": 0.0, "acu": 0.5, "min_acu": 0.5, "max_acu": 16, "warming": true, "cost_usd_hr": 0.06, "connection_pressure": 1.4 } ] }, "reward": -0.12, "done": false } ``` Even though sim-wide `cpu_util` is `0.95` (driven by the compute tier) and sim-wide `connection_pressure` is a benign `0.8`, the `serverless[0]` entry reveals the DB is still `warming` (`cpu_util` 0), parked at the `cost_usd_hr` floor, yet its own `connection_pressure` is already `1.4` against its small ACU-floor pool (~200 connections per ACU = ~100 at 0.5 ACU). An agent training on multi-resource topologies should read `metrics.serverless[i]` for per-DB warming, cost, and pool signals rather than relying on the masked aggregates. **`metrics.connection_pressure` in multi-DB topologies**: The sim-wide `metrics.connection_pressure` is computed as total estimated connections divided by the **sum** of every database's pool. In a single-DB simulation it equals that database's own saturation ratio directly. When the simulation contains an Aurora Serverless v2 database, use the `metrics.serverless` array to inspect per-DB `connection_pressure`, `acu`, and `warming` state alongside the sim-wide aggregate — the `serverless` array is the right per-DB diagnostic tool, not a separate `databases` field. **Per-step tick rate (`tick_seconds`)**: Each step request may include an optional `tick_seconds` integer (1–3600) to override the episode-level clock advancement for that step only. Use large values (e.g. 300 s) during a warm-up phase to fast-forward through startup noise, then switch to smaller values (e.g. 60 s) for fine-grained training. The actual value used is reflected in `observation.tick_seconds` in the response. Example two-phase pattern: run 20 warm-up steps at `tick_seconds=300` (covering ~1.7 h of simulated time), then switch to `tick_seconds=60` for the main training loop. **Provider-specific notes**: - AWS: EC2 warm-up ~30 s; default cooldown 300 s. - AWS (`aurora-serverless`): 2–4 step ACU scale-out delay after `add_resource`; `cost_usd_hr` ramps over 3–6 steps to steady state; `cpu_util` 20–70 % at steady state for OLTP; reverts to `minCapacity` floor cost within 1–2 steps of idle. See "Aurora Serverless v2 — expected observation shape" above for full details. - GCP: Managed instance group warm-up ~45 s; default cooldown 120 s. - Azure: VM Scale Set provisioning ~60 s; default cooldown 300 s. - OCI: Flex shape scaling modeled with OCPU granularity; Autonomous DB burst handled automatically. - DigitalOcean: Droplet cold-start ~30 s; default cooldown 180 s. ### Infrastructure Optimization API Analyzes a simulation architecture and generates tested variations ranked by cost and performance. | Method | Path | Auth | Description | |---|---|---|---| | POST | /analysis/optimize | Bearer | Submit an infrastructure optimization job | | GET | /analysis/jobs/{id} | Bearer | Get optimization job status | | GET | /analysis/jobs/{id}/recommendations | Bearer | Get ranked optimization recommendations | ### Predictive Scaling API Validate infrastructure against traffic forecasts and optimize autoscaling thresholds. | Method | Path | Auth | Description | |---|---|---|---| | POST | /predictions/validate | Bearer | Submit a predictive scaling validation job with a traffic forecast | | POST | /predictions/optimize-thresholds | Bearer | Submit a threshold optimization job | | GET | /predictions/jobs/{jobId} | Bearer | Get prediction job status (supports polling) | | GET | /predictions/jobs/{jobId}/stream | Bearer | Subscribe to job progress via Server-Sent Events (SSE) | | GET | /predictions/jobs/{jobId}/results | Bearer | Get final prediction or optimization results | **Result payload includes**: Recommended scale-out/scale-in thresholds, projected cost at recommended settings, SLA violation risk forecast, detected bottlenecks, and confidence intervals. **Traffic forecast requirements**: At least 5 distinct load-level steps covering a minimum of 60 simulation steps, with strictly increasing timestamps and a clear ramp-up, sustained peak, and ramp-down phase. **Predictive scaling quickstart — Aurora Serverless v2 as a database resource**: ```json { "simulationId": "sim-abc123", "trafficForecast": { "name": "Aurora Serverless Peak Test", "description": "Ramp-up to peak, sustained load, ramp-down", "dataPoints": [ { "timestamp": 0, "rps": 50, "label": "Baseline" }, { "timestamp": 25, "rps": 300, "label": "Ramp-up" }, { "timestamp": 50, "rps": 800, "label": "Peak" }, { "timestamp": 75, "rps": 400, "label": "Decline" }, { "timestamp": 100, "rps": 80, "label": "Post-peak baseline" } ] }, "testSteps": 100 } ``` Include `aurora-serverless` in prediction payloads whenever the simulation contains a variable-capacity database. The engine models a **2–4 step ACU ramp delay** after a load increase before the new capacity is fully available, and a **3–6 step incremental cost delta** as ACUs increase one tier at a time toward the new steady state — meaning projected cost during a traffic ramp is lower in early steps and reaches the provisioned-equivalent level only after the ramp completes. Both effects appear in the result payload's `bottlenecks` and `costProjection` fields so agents can account for the lag when setting scale-out lead time. ### Chaos Engineering API Inject failures to discover architectural weak points. Returns resilience scores, vulnerability analysis, and remediation recommendations. | Method | Path | Auth | Description | |---|---|---|---| | GET | /chaos/scenarios | Public | List pre-built chaos scenarios | | POST | /chaos/run | Bearer | Submit a chaos engineering test (single failure injection) | | GET | /chaos/jobs/{jobId} | Bearer | Get chaos job status | | GET | /chaos/jobs/{jobId}/stream | Bearer | Subscribe to job progress via Server-Sent Events (SSE) | | GET | /chaos/jobs/{jobId}/results | Bearer | Get chaos results and resilience report | | POST | /chaos/batch | Bearer | Submit multiple chaos jobs in parallel | | GET | /chaos/batch/{batchId} | Bearer | Get batch job status | | GET | /chaos/batch/{batchId}/results | Bearer | Get all batch results aggregated | **Supported failure types** (`customInjections[].failureType`): `kill_instance`, `zone_outage`, `database_crash`, `database_slowdown`, `database_overload`, `network_partition`, `cpu_stress`, `memory_pressure`. **Zone-failure naming — three surfaces, three names:** | Name | Where it appears | Context | |---|---|---| | `zone_outage` | `customInjections[].failureType` in `POST /chaos/run` | Async chaos API custom injection | | `az_outage` | `type` in `POST /simulations/{id}/failures` | Synchronous failure-injection API | | `zone_failure` | `scenarioId` in `POST /chaos/run` or `POST /chaos/batch` | Pre-built scenario ID | `database_overload` models **connection-pool saturation** (not a hard crash like `database_crash`): the targeted database's connection headroom shrinks and latency climbs, but the instance stays reachable. It is accepted by **both** the asynchronous chaos API (`POST /chaos/run`, as a `customInjections[].failureType` or via the prebuilt `scenarioId: "database_overload"`) **and** the synchronous failure-injection API (`POST /simulations/{id}/failures`, as a `type`). In a multi-cloud simulation, a one-sided `database_overload` only pressures the targeted database — connection load is charged on the share of traffic actually routed to each database, so a quiet, non-targeted database no longer emits spurious connection-pressure events. Aurora Serverless v2 (`aurora-serverless`) is a valid target for `database_crash` and `database_slowdown` failures. Use the resource `id` assigned when the resource was added to the simulation. **Chaos quickstart — `database_overload` via prebuilt scenario**: ```json { "simulationId": "sim-abc123", "scenarioId": "database_overload", "duration": 300 } ``` **Chaos quickstart — `database_overload` via custom injection (targeting one database)**: ```json { "simulationId": "sim-abc123", "customInjections": [ { "failureType": "database_overload", "targetResourceId": "db-primary", "intensity": 85, "duration": 300 } ] } ``` **`POST /chaos/run` response shape**: the `202` body returns a top-level `jobId` (convenience mirror of `job.id`) alongside the nested `job` object: ```json { "jobId": "job-abc123", "job": { "id": "job-abc123", "type": "chaos_test", "status": "pending", "simulationId": "sim-abc123", "createdAt": "2026-06-13T00:00:00.000Z" }, "message": "Chaos test started. Use GET /chaos/jobs/{id} to check status." } ``` **Chaos quickstart — `database_crash` targeting an Aurora Serverless v2 resource**: ```json { "simulationId": "sim-abc123", "failureType": "database_crash", "targetResourceId": "db-sv2", "durationSteps": 5 } ``` **Chaos quickstart — `database_slowdown` targeting an Aurora Serverless v2 resource**: Unlike `database_crash` (which models a hard instance failure), `database_slowdown` simulates ACU throttling and connection-pool pressure on Aurora Serverless v2 — the latency spikes and capacity exhaustion that occur when traffic exceeds the configured `maxCapacity` or when the ACU scaling lag cannot keep up with a sudden burst. Use this failure type to verify that upstream services degrade gracefully (retry budgets, circuit breakers, read-replica fallback) rather than failing outright. ```json { "simulationId": "sim-abc123", "failureType": "database_slowdown", "targetResourceId": "db-sv2", "durationSteps": 5 } ``` **Aurora Serverless v2 recovery behavior**: When `database_crash` targets an `aurora-serverless` resource, the simulation models a **2–4 step ACU warm-up period** after the crash ends before full query throughput is restored. During those warm-up steps the resource appears in the observation with reduced capacity and elevated latency even though the failure injection has technically ended. The result payload's `timeToRecover` estimate includes this warm-up window, and `affectedServices` will list upstream compute resources that remain partially degraded until ACU scaling completes. **Chaos batch quickstart — combining `database_crash` and `database_slowdown` against Aurora Serverless v2**: Submitting both failure types in a single `/chaos/batch` call lets you test two distinct failure modes in parallel rather than sequentially. `database_crash` models a hard instance failure (connection refused, immediate downstream errors), while `database_slowdown` models ACU throttling and connection-pool pressure (latency spikes, partial degradation). Running them together reveals whether your application handles both gracefully at the same time — for example, whether a circuit breaker that trips on hard failures also activates on slow responses, or whether retry logic intended for transient slowdowns masks a total outage. ```json { "simulationId": "sim-abc123", "scenarios": [ { "scenarioId": "database_crash", "duration": 300 }, { "scenarioId": "database_slowdown", "duration": 300 } ] } ``` The `202` response returns a `batchId` and a `type: "batch_chaos_test"` job object. Poll `GET /chaos/batch/{batchId}` for overall batch status and `GET /chaos/batch/{batchId}/results` for the aggregated resilience reports once all jobs complete. **Chaos multi-fault cascade — zone + database**: Use `customInjections` with multiple entries in a single `POST /chaos/run` call to inject correlated failures simultaneously. This is the reliable way to test whether upstream services handle both a zone outage and a database slowdown at the same time — for example, whether retry logic meant for transient slowdowns also activates correctly when the primary AZ is unreachable: ```json { "simulationId": "sim-abc123", "customInjections": [ { "failureType": "zone_outage", "targetZone": "us-east-1a", "duration": 120 }, { "failureType": "database_slowdown", "targetResourceId": "db-primary", "intensity": 80, "duration": 120 } ] } ``` **Result payload includes**: Resilience score (0–100), affected services, blast radius estimate, time-to-recover estimate, detected vulnerabilities, and remediation recommendations. **Resilience grade caveat**: The `grade` field reflects a static vulnerability analysis of your architecture (SPOF detection, redundancy gaps). It may not change between a single-fault run and a multi-fault run on already-resilient topologies, because the grade measures architectural exposure — not live error rate. To measure severity differences between fault combinations, pair `POST /chaos/run` (vulnerability report) with the synchronous `POST /simulations/{id}/failures` + step-loop pattern (live metrics). ### Multi-Cloud Strategy Exploration API Generate and analyze multi-cloud architecture variants to identify optimal provider combinations. | Method | Path | Auth | Description | |---|---|---|---| | POST | /multi-cloud/explore | Bearer | Submit a multi-cloud strategy exploration job | | GET | /multi-cloud/jobs/{jobId} | Bearer | Get job status (supports polling) | | GET | /multi-cloud/jobs/{jobId}/stream | Bearer | Subscribe to job progress via Server-Sent Events (SSE) | | GET | /multi-cloud/jobs/{jobId}/partial-results | Bearer | Get strategies accumulated so far while a job is running (isComplete: false until terminal) | | GET | /multi-cloud/jobs/{jobId}/results | Bearer | Get final exploration results and comparison report. **Only returns data once the job has finished** (status `completed`). While the job is still `pending` or `running` it returns HTTP 400 `INVALID_REQUEST`; a `failed` job returns HTTP 500. To read strategies as they accumulate during a run, poll `/multi-cloud/jobs/{jobId}/partial-results` instead. | **Polling pattern**: After `POST /multi-cloud/explore`, poll `GET /multi-cloud/jobs/{jobId}` (or subscribe via `/stream`) until `status` is `completed`, then call `/results` once for the final ranked strategies and comparison report. Do not poll `/results` for in-progress data — use `/partial-results` for that. **Agent tip — request body field placement**: The request body for `POST /multi-cloud/explore` has five optional top-level fields alongside `workloadProfile`: `optimizationWeights`, `beginnerMode`, `maxCostPerHour`, `errorBudgetPct`, and `modifiers`. These are siblings of `workloadProfile`, not nested inside it. If you place any of these fields *inside* `workloadProfile`, the server silently ignores them and responds 202 — your weights and constraints will have no effect. Always send them at the top level. **`modifiers` field** (optional object): Apply pricing discounts to the exploration run. All sub-fields default to off. Sub-fields: `awsCommitment` (`"on-demand"` | `"1yr"` | `"3yr"`) — AWS Savings Plan tier (~40% off 1-yr, ~60% off 3-yr); `azureHybridBenefit` (boolean) — Azure Hybrid Benefit (~40% off Azure compute/DB for existing Microsoft licence holders); `spotEligible` (boolean) — Spot/Preemptible VM pricing (AWS ~70% off, GCP ~80% off, Azure ~75% off, OCI ~50% off; DigitalOcean has no spot offering); `oracleLicenseHolder` (boolean) — OCI BYOL note (~50% off OCI database costs for existing Oracle SE/EE licence holders, informational only). **`optimizationWeights` strict validation**: The `optimizationWeights` object rejects unknown keys with HTTP 400. Only `cost`, `latency`, and `vendorLockIn` are accepted. Example: `{ "cost": 0.4, "latency": 0.4, "vendorLockIn": 0.2 }`. Adding any extra key (e.g. `"reliability": 0.1`) returns 400. Values need not sum to 1.0 — the engine normalises them automatically. **`estimateDisclaimer` field**: Completed exploration results include an `estimateDisclaimer` string on `GET /multi-cloud/jobs/{jobId}/results`, `GET /multi-cloud/jobs/{jobId}` (when status is `completed`), and the UI preview endpoints. This is a static fidelity reminder: explore figures are flight-simulator-style planning estimates, not actual billing data. They reflect baseline on-demand rates under typical load. Internet egress is estimated and included in `totalCostPerHour` via the `egressCostPerHour` field in each strategy's `costBreakdown`. Still excluded: free-tier and Always-Free egress allowances, bandwidth pack credits (e.g. DigitalOcean's included TB/month), monitoring and support surcharges, sustained-peak ACU ramp-up for serverless tiers, free-tier and Always-Free credit offsets, and reserved-instance / committed-use / spot discounts. Allocations with different `skuClass` labels are not directly cost-comparable; see `crossClassNote` on any strategy that mixes non-equivalent product tiers. Actual spend can differ materially. Validate top candidates by materialising them as owned simulations and stepping at production RPS before making infrastructure commitments. **SLO constraint fields** (both optional, rank-last rather than filter): - `maxCostPerHour` (number, > 0): Budget ceiling in USD/hr. Strategies whose `totalCostPerHour` exceeds this value are moved to the tail of the ranked list (not filtered out), so you can see both in-budget and over-budget options in a single response. - `errorBudgetPct` (number, 0–100): SLO error-budget percentage. The engine models an implied error rate per provider count (single-provider ~0.50%, two-provider ~0.15%, three+ ~0.05%). Strategies whose implied rate exceeds this threshold are ranked last. Setting `0.1` effectively demotes all single-provider strategies below multi-provider alternatives. **SSE event types** (`GET /multi-cloud/jobs/{jobId}/stream`): the stream emits named events you can subscribe to individually: | Event | Payload | When | |---|---|---| | `init` | `{ jobId, status, progress, strategiesGenerated }` | Once, immediately on connect (reflects current job state). | | `strategy` | a single raw strategy object | For each strategy already accumulated, then for each new one as it is generated. | | `strategies-generated` | `{ strategiesGenerated, progress }` | Whenever the running strategy count changes — a dedicated live counter signal, emitted independently of `progress` so it stays current during the 0→40% generation phase even when the progress percentage hasn't ticked. | | `progress` | `{ progress, strategiesGenerated }` | Whenever the progress percentage changes. | | `complete` | `{ status, progress, strategiesGenerated, comparisonReport, latencyWarning, completedAt, error }` | Once, when the job reaches a terminal state (`completed`, `failed`, or `cancelled`); the stream then closes. | **Result payload includes**: Per-variant cost breakdown, latency estimates, vendor lock-in score, availability model, migration complexity rating, and multi-objective optimization ranking. DigitalOcean is a first-class candidate and typically produces the lowest-cost strategies. **Explore estimates vs. live /step values — read this before committing to a strategy**: The explore engine produces comparative estimates, not guaranteed runtime metrics. Two fields in particular require care: - `cost_usd_hr` in explore results — for serverless tiers (e.g. Aurora Serverless v2, Cloud Run, Lambda) this reflects the **ACU-floor / minimum-billing cost** at near-zero load, not the cost you will see at production RPS. At peak traffic the actual cost will be higher once ACUs ramp up. For provisioned tiers the figure is the baseline on-demand hourly rate without data-transfer, monitoring, or support surcharges. - `avgLatencyMs` in explore results — this is a **low-traffic baseline estimate** derived from provider region benchmarks, not a P95 or P99 at your production request rate. Under high concurrency, actual latency will be higher due to connection-pool pressure, cold-start ramp, and network jitter. **Recommendation**: treat explore output as a shortlist, not a final answer. Once you identify the top one or two strategies, materialise them as owned simulations (`POST /simulations`), apply your production traffic pattern, and step at target RPS to observe `metrics.latencyP95`, `metrics.costPerHour`, and `metrics.connectionPressure` under realistic load before committing. **`vendorLockInScore` direction**: In all explore results and comparison reports, `vendorLockInScore` is a **lock-in score** 0–100 where **higher = more locked in** (harder to migrate away). Single-provider strategies score 55–84 depending on how proprietary the DB service is (Aurora Serverless scores ~80, standard RDS ~62); multi-provider strategies score 20–50 depending on traffic distribution and provider count. A score of 75 for a single-provider AWS Aurora Serverless strategy means high lock-in; a score of 30 for a balanced AWS/GCP mix means low lock-in. Lower scores are preferable if portability is a goal. **New response fields** (available in `strategy.metrics` and per-strategy objects): - `p95LatencyMs` (number): Estimated P95 latency in milliseconds, computed as `avgLatencyMs × 1.5`. Use this to check whether a strategy's tail latency fits within a strict SLA before materialising it as a simulation. - `suggestedResources` (array of objects): Materializable SKU objects derived from each allocation. Each entry has `{provider, resourceType, size, count, hourlyRate}` — e.g. `{provider:"aws", resourceType:"compute", size:"t3.medium", count:4, hourlyRate:0.096}`. Use these to pre-populate infrastructure manifests or Terraform modules directly from the explore result. - `securityRecommendations` (array of strings): WAF/firewall palette IDs recommended for each provider footprint (e.g. `"aws-waf"`, `"gcp-cloud-armor"`, `"azure-waf"`, `"oci-waf"`). Separate from `suggestedResources` to keep SKU objects and security identifiers cleanly distinct. **SKU equivalence labels and cross-class notes** (on `strategy.allocations[]` and `strategy`): Each allocation carries three classification fields. `skuClass` is the primary label (compute wins when non-default; see precedence below). `computeSkuClass` and `databaseSkuClass` expose each dimension independently so cross-class mismatches are never masked. Allocations that share the same `skuClass` are cost-comparable at the class level; those with different values are not directly comparable. **Precedence for `skuClass`**: if `computeSkuClass` is `bare-metal-compute`, `free-tier-compute`, or `do-droplet`, that value is used as `skuClass` even when a `databaseSkuClass` is also present. For standard dedicated-vCPU compute (`general-compute`), the database class is promoted when set; the final fallback is `general-compute`. The eight class values are: | class | Dimension | Examples | |---|---|---| | `general-compute` | compute | Standard dedicated-vCPU VMs — EC2, Compute Engine, Azure VMs, OCI VM.Standard/Flex | | `do-droplet` | compute | DigitalOcean Droplets — shared-vCPU cloud VMs; different resource model from dedicated-vCPU instances | | `free-tier-compute` | compute | Always-free / zero-cost compute — OCI Always Free AMD micro VMs (costs excluded from totals) | | `bare-metal-compute` | compute | Dedicated bare-metal servers — OCI BM.Standard3.64, BM.Optimized3.36 | | `managed-rdbms` | database | Provisioned relational DBs — RDS, Cloud SQL, Azure SQL, … | | `oci-heatwave` | database | OCI MySQL HeatWave DB System and HeatWave Analytics Cluster — in-memory analytics accelerator; distinct billing model from managed-rdbms | | `serverless-db` | database | Pay-per-use / auto-scaling DBs — Aurora Serverless, Cloud Spanner, Autonomous DB, … | | `managed-nosql` | database | Wide-column / key-value NoSQL — Bigtable SSD/HDD, … | `crossClassNote` is present on a strategy when its allocations span more than one class in either the **compute** dimension (comparing `computeSkuClass` values) or the **database** dimension (comparing `databaseSkuClass` values). Each dimension is checked independently — a compute-tier mismatch is never masked by a shared database tier, and vice-versa. Absent when all allocations share the same class in both dimensions. **Simulation fidelity framing**: All cost and latency figures produced by the explore engine are flight-simulator-style planning estimates, not actual billing data. They are calibrated against public pricing pages (see `/fidelity`). Internet egress is estimated and included in `totalCostPerHour` via `egressCostPerHour`. Still excluded: free-tier and Always-Free egress allowances, bandwidth pack credits (e.g. DigitalOcean's included TB/month), monitoring/support surcharges, free-tier and Always-Free credit offsets, reserved-instance / committed-use / spot discounts, and the ACU ramp-up cost that serverless tiers incur at peak load. The `skuClass` label lets you quickly spot when two strategies are comparing non-equivalent tiers (e.g. a bare-metal OCI strategy vs a standard Droplet strategy, or provisioned RDS vs Aurora Serverless) before committing to a cost-difference figure. The `estimateDisclaimer` field in the explore result reflects these caveats for inline reference. **Aurora Serverless v2 as a cost-aware database candidate**: When exploring AWS-anchored strategies, the engine considers `aurora-serverless` (Aurora Serverless v2) as a low-cost database substitute for provisioned `aurora-postgresql` instances. Aurora Serverless v2 scales ACUs (Aurora Capacity Units) continuously between `minCapacity` and `maxCapacity`, so cost tracks actual load rather than peak provisioned size. It is the recommended choice when the workload is variable or has long idle periods. Exploration variants that include `aurora-serverless` will show a lower `cost_usd_hr` estimate compared with equivalent fixed-instance Aurora variants, along with a higher `scalability` rating and a lower `vendor_lock_in` penalty than proprietary NoSQL alternatives. **Cold-start trade-off**: ACU ramp-up from near-zero capacity can add 1–5 s of latency on the first request after an idle period; do not select `aurora-serverless` for latency-sensitive workloads (e.g. real-time APIs with strict P99 SLAs) unless a `minCapacity` ≥ 1 ACU is configured to keep the cluster warm. **Example: AWS architecture variant substituting provisioned Aurora with Aurora Serverless v2** Input simulation uses a provisioned `aurora-postgresql` instance. The exploration engine emits a cost-optimized AWS variant in the results: ```json { "variantId": "aws-cost-optimized", "provider": "aws", "resources": [ { "type": "compute", "provider": "aws", "name": "api-server", "size": "t3.medium" }, { "type": "database", "provider": "aws", "name": "primary-db", "serviceFamily": "aurora-serverless", "minCapacity": 0.5, "maxCapacity": 8 } ], "estimatedCostUsdHr": 0.09, "notes": "Aurora Serverless v2 replaces the provisioned aurora-postgresql instance; ACUs scale to near-zero during idle windows, reducing cost by ~40% for variable workloads." } ``` **Important**: `serviceFamily` shown in explore *result* objects (like `"serviceFamily": "aurora-serverless"` above) is part of the variant descriptor returned by the engine — it is **not** a field inside the `workloadProfile` request body. The `WorkloadProfile` schema does not include `serviceFamily`; any such property placed inside `workloadProfile` is silently ignored. The explore engine automatically considers Aurora Serverless v2 alongside provisioned Aurora instances for AWS-anchored strategies — submit a `workloadProfile` describing your compute instances, traffic, and latency requirements, and the engine generates both serverless and provisioned variants without any extra input field. **Side-by-side cost comparison — provisioned `aurora-postgresql` vs `aurora-serverless`**: The exploration engine returns both variants in the same results payload so agents can compare directly. Example response excerpt: ```json [ { "variantId": "aws-provisioned-db", "provider": "aws", "resources": [ { "type": "compute", "provider": "aws", "name": "api-server", "size": "t3.medium" }, { "type": "database", "provider": "aws", "name": "primary-db", "serviceFamily": "aurora-postgresql", "instanceClass": "db.r6g.large" } ], "estimatedCostUsdHr": 0.15, "notes": "Fixed-capacity provisioned Aurora PostgreSQL; cost is constant regardless of actual load." }, { "variantId": "aws-serverless-db", "provider": "aws", "resources": [ { "type": "compute", "provider": "aws", "name": "api-server", "size": "t3.medium" }, { "type": "database", "provider": "aws", "name": "primary-db", "serviceFamily": "aurora-serverless", "minCapacity": 0.5, "maxCapacity": 8 } ], "estimatedCostUsdHr": 0.09, "notes": "Aurora Serverless v2 scales ACUs to near-zero during idle windows. ~40% cost reduction versus the provisioned variant for variable workloads." } ] ``` Key fields for cost-aware selection: `estimatedCostUsdHr` is the per-hour estimate at average (not peak) load. For workloads with long idle periods or high variance, `aurora-serverless` will show a materially lower figure than `aurora-postgresql` with a fixed instance class. Prefer `aurora-serverless` when `estimatedCostUsdHr` is at least 20% lower and the workload is not latency-sensitive during cold ACU ramp-up. **GCP database tier — Cloud SQL, Cloud Spanner, Bigtable SSD, and Bigtable HDD**: When exploring GCP-anchored strategies, the engine considers four database service families as candidates: `cloud-sql` (provisioned PostgreSQL/MySQL instance), `cloud-spanner` (fully managed, horizontally scalable, globally distributed), `bigtable-ssd` (wide-column NoSQL, SSD-backed, low-latency analytics), and `bigtable-hdd` (wide-column NoSQL, HDD-backed, cost-optimised batch). Cloud SQL is lowest cost for single-region, schema-heavy, transactional workloads. Cloud Spanner scales horizontally without sharding and offers 99.999% multi-region SLA at higher base cost. Bigtable SSD delivers single-digit millisecond reads at scale for time-series and IoT workloads. Bigtable HDD is ~74% cheaper per node than SSD and is suited for batch analytics and archival access where latency tolerance exceeds ~50 ms. The engine surfaces all four variants so agents can evaluate the cost/capability trade-off directly. **Side-by-side cost comparison — `cloud-sql` vs `cloud-spanner` vs `bigtable-ssd` vs `bigtable-hdd`**: The exploration engine returns all variants in the same results payload so agents can compare directly. Example response excerpt: ```json [ { "variantId": "gcp-cloud-sql", "provider": "gcp", "resources": [ { "type": "compute", "provider": "gcp", "name": "api-server", "size": "n2-standard-2" }, { "type": "database", "provider": "gcp", "name": "primary-db", "serviceFamily": "cloud-sql", "instanceClass": "db-n1-standard-2" } ], "estimatedCostUsdHr": 0.12, "notes": "Provisioned Cloud SQL PostgreSQL instance (2 vCPU, 7.5 GB). Fixed cost regardless of load; well-suited for small, steady-state, single-region workloads." }, { "variantId": "gcp-cloud-spanner", "provider": "gcp", "resources": [ { "type": "compute", "provider": "gcp", "name": "api-server", "size": "n2-standard-2" }, { "type": "database", "provider": "gcp", "name": "primary-db", "serviceFamily": "cloud-spanner", "processingUnits": 100 } ], "estimatedCostUsdHr": 0.28, "notes": "Cloud Spanner at 100 processing units (0.1 node). ~2.3x the cost of Cloud SQL at small scale, but scales horizontally without sharding, offers 99.999% multi-region SLA, and eliminates manual capacity planning as write throughput grows." }, { "variantId": "gcp-bigtable-ssd", "provider": "gcp", "resources": [ { "type": "compute", "provider": "gcp", "name": "api-server", "size": "n2-standard-2" }, { "type": "database", "provider": "gcp", "name": "primary-db", "serviceFamily": "bigtable-ssd", "nodes": 1 } ], "estimatedCostUsdHr": 0.74, "notes": "Cloud Bigtable SSD node ($0.65/node-hr). Wide-column NoSQL with single-digit ms latency at millions of rows/sec. Best for time-series, IoT telemetry, and low-latency analytics; no SQL support." }, { "variantId": "gcp-bigtable-hdd", "provider": "gcp", "resources": [ { "type": "compute", "provider": "gcp", "name": "api-server", "size": "n2-standard-2" }, { "type": "database", "provider": "gcp", "name": "primary-db", "serviceFamily": "bigtable-hdd", "nodes": 1 } ], "estimatedCostUsdHr": 0.26, "notes": "Cloud Bigtable HDD node ($0.17/node-hr). ~74% cheaper than SSD; suited for batch analytics and archival workloads with p99 latency tolerance above ~50 ms." } ] ``` Key fields for cost-aware selection: at small, steady-state load `cloud-sql` will show a materially lower `estimatedCostUsdHr` than `cloud-spanner`. Prefer `cloud-spanner` when the workload requires horizontal write scaling, multi-region strong consistency, or the projected growth path would require manual sharding of a Cloud SQL instance. Prefer `cloud-sql` when `estimatedCostUsdHr` savings exceed 50% and the workload fits within a single provisioned instance with no cross-region consistency requirement. Prefer `bigtable-ssd` for high-throughput NoSQL workloads (IoT, time-series, recommendations) where p99 read latency must stay below 10 ms. Prefer `bigtable-hdd` when the same NoSQL data model is acceptable but the workload is batch-oriented or archival and a ~74% cost reduction per node outweighs the higher latency. **Azure database tier — Azure SQL vs Cosmos DB**: When exploring Azure-anchored strategies, the engine considers both `azure-sql` (provisioned relational database, SQL Server-compatible) and `cosmos-db` (globally distributed, multi-model, serverless or provisioned throughput) as database candidates. Azure SQL is lower cost for single-region, schema-heavy, transactional workloads with predictable concurrency at moderate throughput. Cosmos DB charges per Request Unit per second (RU/s): at its 400 RU/s minimum the entry cost is low, but RU/s provisioning scales linearly — at high write concurrency Cosmos DB can exceed Azure SQL cost significantly. Cosmos DB offers single-digit-millisecond latency at any scale, turnkey global distribution across Azure regions, and multiple consistency levels — making it the preferred choice when the workload requires low-latency reads at global scale, schema flexibility, or multi-region active-active writes. The engine surfaces both variants so agents can evaluate the cost/capability trade-off directly. **Side-by-side cost comparison — `azure-sql` vs `cosmos-db`**: The exploration engine returns both variants in the same results payload so agents can compare directly. Example response excerpt: ```json [ { "variantId": "azure-azure-sql", "provider": "azure", "resources": [ { "type": "compute", "provider": "azure", "name": "api-server", "size": "Standard_D2s_v3" }, { "type": "database", "provider": "azure", "name": "primary-db", "serviceFamily": "azure-sql", "tier": "GeneralPurpose", "vCores": 2 } ], "estimatedCostUsdHr": 0.18, "notes": "Provisioned Azure SQL General Purpose, 2 vCores. Fixed cost regardless of request volume; well-suited for relational, single-region workloads with predictable concurrency and structured schemas." }, { "variantId": "azure-cosmos-db", "provider": "azure", "resources": [ { "type": "compute", "provider": "azure", "name": "api-server", "size": "Standard_D2s_v3" }, { "type": "database", "provider": "azure", "name": "primary-db", "serviceFamily": "cosmos-db", "throughputModel": "provisioned", "requestUnitsPerSecond": 400 } ], "estimatedCostUsdHr": 0.048, "notes": "Cosmos DB provisioned at 400 RU/s (minimum). Lower entry cost at minimal throughput, but RU/s charges scale linearly with required throughput — at high write volumes Cosmos DB can exceed Azure SQL cost. Offers multi-model API (SQL, MongoDB, Cassandra), tunable consistency, and turnkey multi-region replication not available in Azure SQL." } ] ``` Key fields for cost-aware selection: at low throughput `cosmos-db` entry cost (400 RU/s minimum) can appear lower than `azure-sql`, but RU/s charges scale linearly — at sustained high write concurrency `azure-sql` will show a materially lower `estimatedCostUsdHr`. Prefer `cosmos-db` when the workload requires global distribution, sub-10 ms reads at scale, schema flexibility, or multi-region active-active writes. Prefer `azure-sql` when the workload is single-region, relational, and concurrency is predictable — the fixed vCore pricing model becomes significantly cheaper once Cosmos DB RU/s provisioning would need to exceed ~2000 RU/s to serve the load. **Azure SQL Managed Instance tiers — MI_GP_Gen5_4 vs MI_BC_Gen5_4**: SQL Managed Instance (SQL MI) is a fully managed deployment option with near 100% SQL Server compatibility, targeting lift-and-shift migrations. The simulator tracks two committed reference shapes for East US (June 2026): | Shape | SKU | vCores | RAM | Committed rate | Monthly approx. | |---|---|---|---|---|---| | MI_GP_Gen5_4 | General Purpose, Gen5, 4 vCore | 4 | 20.4 GB | $0.741/hr | ~$541/mo | | MI_BC_Gen5_4 | Business Critical, Gen5, 4 vCore | 4 | 20.4 GB | $1.906/hr | ~$1,391/mo | The General Purpose tier uses remote storage (Azure Premium storage, ~5.5 ms I/O latency) and is suited for workloads that can tolerate occasional storage I/O latency. The Business Critical tier provisions local SSD storage with a built-in read-scale secondary replica, delivering sub-millisecond I/O and built-in high availability at roughly 2.6× the General Purpose cost. Choose General Purpose for cost-sensitive, write-heavy OLTP workloads where remote storage latency is acceptable. Choose Business Critical when the workload has strict P99 latency requirements (e.g. ≤ 5 ms reads), needs an in-region read replica for reporting without extra licensing cost, or requires maximum availability (BC provides a built-in local secondary replica that survives storage failures, giving higher effective resilience than GP's remote-storage model despite both tiers publishing a 99.99% uptime SLA). Both shapes are tracked in the weekly pricing drift check (`azure-sql-mi-gp-gen5-4` and `azure-sql-mi-bc-gen5-4`) and appear in the Fidelity benchmark status panel alongside Azure SQL Database and Cosmos DB entries. **OCI database tier — Autonomous Transaction Processing (ATP) vs MySQL HeatWave (with and without HeatWave cluster)**: When exploring OCI-anchored strategies, the engine considers three database variants: `autonomous-db` (Oracle Autonomous Transaction Processing, self-driving, self-securing, ECPU-billed), `mysql-heatwave` (managed MySQL DB System on E4.Flex compute, no cluster — pure OLTP), and `mysql-heatwave-cluster` (same DB System plus one in-memory HeatWave cluster node for HTAP analytics). ATP is the higher-cost option at entry level but bundles Oracle-managed patching, in-memory columnar query acceleration, automatic index tuning, and serverless ECPU scaling — making it well-suited for mixed OLTP/analytics workloads that need zero-DBA management and predictable SLAs. MySQL HeatWave (DB System without the HeatWave cluster) is significantly cheaper for pure transactional MySQL workloads: at 2 OCPU / 16 GB on E4.Flex the all-in hourly rate is materially lower than ATP's 2-ECPU baseline, and the familiar MySQL wire protocol avoids any application re-platforming cost. Adding a HeatWave cluster node unlocks in-database analytics on live OLTP data without ETL, but at a substantially higher hourly cost ($1.67/node-hr for the cluster node alone). The engine surfaces all three variants so agents can evaluate the full cost/capability spectrum directly. **Side-by-side cost comparison — `autonomous-db` vs `mysql-heatwave` vs `mysql-heatwave-cluster`**: The exploration engine returns all three variants in the same results payload so agents can compare directly. Example response excerpt: ```json [ { "variantId": "oci-autonomous-db", "provider": "oci", "resources": [ { "type": "compute", "provider": "oci", "name": "api-server", "size": "VM.Standard.E4.Flex" }, { "type": "database", "provider": "oci", "name": "primary-db", "serviceFamily": "autonomous-db", "tier": "standard", "ecpus": 2 } ], "estimatedCostUsdHr": 0.789, "notes": "OCI Autonomous AI Transaction Processing (Standard), 2 ECPUs at $0.336/ECPU-hr plus blended storage (~$0.117/hr). OCI rebranded Autonomous Database as Autonomous AI (part B95702). Self-driving: automated patching, tuning, and scaling. Built-in in-memory columnar processing for mixed OLTP/analytics. Best when zero-DBA operation, Oracle-compatible SQL, or HTAP capability is required." }, { "variantId": "oci-mysql-heatwave", "provider": "oci", "resources": [ { "type": "compute", "provider": "oci", "name": "api-server", "size": "VM.Standard.E4.Flex" }, { "type": "database", "provider": "oci", "name": "primary-db", "serviceFamily": "mysql-heatwave", "shape": "MySQL.VM.Standard.E4.Flex", "ocpus": 2, "memoryGb": 16 } ], "estimatedCostUsdHr": 0.074, "notes": "OCI MySQL HeatWave DB System, 2 OCPU / 16 GB on E4.Flex — no HeatWave cluster. $0.025/OCPU-hr × 2 + $0.0015/GB-hr × 16 = $0.074/hr. Standard MySQL wire protocol — zero application re-platforming. Lowest-cost OCI database option for pure transactional MySQL workloads. To add in-database HTAP analytics on live OLTP data, see the `oci-mysql-heatwave-cluster` variant below ($0.0995/hr with 1 cluster node)." }, { "variantId": "oci-mysql-heatwave-cluster", "provider": "oci", "resources": [ { "type": "compute", "provider": "oci", "name": "api-server", "size": "VM.Standard.E4.Flex" }, { "type": "database", "provider": "oci", "name": "primary-db", "serviceFamily": "mysql-heatwave", "shape": "MySQL.VM.Standard.E4.Flex", "ocpus": 2, "memoryGb": 16 }, { "type": "database-addon", "provider": "oci", "name": "heatwave-cluster", "serviceFamily": "mysql-heatwave-cluster", "nodes": 1, "shape": "HeatWave.512GB" } ], "estimatedCostUsdHr": 0.0995, "notes": "OCI MySQL HeatWave DB System + 1 HeatWave cluster node for HTAP (hybrid transactional/analytical processing). DB System: $0.074/hr (2 OCPU / 16 GB, same as `oci-mysql-heatwave`). HeatWave cluster node: $0.0255/node-hr. Combined: $0.074 + $0.0255 = $0.0995/hr. Enables in-database analytics on live OLTP data without ETL or a separate analytics tier. At $0.0995/hr the combined cost is comparable to `autonomous-db` ($0.789/hr) — choose based on MySQL wire-protocol compatibility requirements and in-database analytics throughput needs." } ] ``` Key fields for cost-aware selection: `autonomous-db` carries roughly twice the hourly cost of a baseline `mysql-heatwave` DB System at equivalent scale, but that premium covers automated DBA operations, Oracle SQL compatibility, and built-in HTAP acceleration. Adding a HeatWave cluster node to the MySQL DB System (`mysql-heatwave-cluster`) pushes the all-in cost to approximately $0.0995/hr — the cluster node add-on ($0.0255/node-hr) is modest and the combined cost is comparable to `autonomous-db` ($0.789/hr). Prefer `autonomous-db` when the workload requires Oracle-compatible SQL, mixed OLTP/analytics queries without a separate analytics tier, or zero-ops database management with automatic index and performance tuning. Prefer `mysql-heatwave` (no cluster) when the application is MySQL-native, the workload is purely transactional, and the cost saving versus ATP exceeds the value of Oracle's self-managing features — the MySQL wire protocol means no driver or ORM changes are needed on migration. Choose `mysql-heatwave-cluster` when MySQL wire-protocol compatibility is a hard requirement **and** in-database analytics on live OLTP data is the primary workload driver; at $0.0995/hr it is a cost-competitive alternative to `autonomous-db` ($0.789/hr) for HTAP workloads. **OCI Block Volume — Ultra High Performance (UHP) tiers**: OCI Block Volume UHP scales linearly from 30 to 120 VPUs/GB. All four tiers share the same volume-level caps (225,000 IOPS, 2,680 MB/s) — the VPU count controls per-GB density, not the absolute caps. Higher VPU tiers saturate those caps on smaller volumes, making them cost-efficient for high-IOPS-density workloads where volume size is constrained. Pricing is based on a ~430 GB reference volume (us-ashburn-1, May 2026). ```json [ { "size": "ultra-high-performance-30vpus", "provider": "oci", "serviceFamily": "block-volume", "estimatedCostUsdHr": 0.041, "iopsMax": 225000, "throughputMbsMax": 2680, "iopsPerGb": 90, "throughputKbpsPerGb": 900, "notes": "OCI Block Volume Ultra High Performance, 30 VPUs/GB. $0.0255/GB-mo base + 20 extra VPUs × $0.00225/VPU/GB-mo = $0.0705/GB-mo; flat sim rate $0.041/hr (~430 GB reference). 90 IOPS/GB and 900 KBPS/GB; volume caps: 225,000 IOPS and 2,680 MB/s. IOPS cap saturates at ~2,500 GB. Baseline UHP tier — lowest per-GB VPU cost; suitable for large volumes with moderate IOPS density." }, { "size": "ultra-high-performance-60vpus", "provider": "oci", "serviceFamily": "block-volume", "estimatedCostUsdHr": 0.082, "iopsMax": 225000, "throughputMbsMax": 2680, "iopsPerGb": 180, "throughputKbpsPerGb": 1800, "notes": "OCI Block Volume Ultra High Performance, 60 VPUs/GB. $0.0255/GB-mo base + 50 extra VPUs × $0.00225/VPU/GB-mo = $0.138/GB-mo; flat sim rate $0.082/hr (~430 GB reference). 180 IOPS/GB and 1,800 KBPS/GB; volume caps unchanged at 225,000 IOPS and 2,680 MB/s. IOPS cap saturates at ~1,250 GB — half the volume size needed vs. 30 VPUs to reach peak IOPS." }, { "size": "ultra-high-performance-90vpus", "provider": "oci", "serviceFamily": "block-volume", "estimatedCostUsdHr": 0.123, "iopsMax": 225000, "throughputMbsMax": 2680, "iopsPerGb": 270, "throughputKbpsPerGb": 2700, "notes": "OCI Block Volume Ultra High Performance, 90 VPUs/GB. $0.0255/GB-mo base + 80 extra VPUs × $0.00225/VPU/GB-mo = $0.2055/GB-mo; flat sim rate $0.123/hr (~430 GB reference). 270 IOPS/GB and 2,700 KBPS/GB; volume caps unchanged at 225,000 IOPS and 2,680 MB/s. IOPS cap saturates at ~834 GB. Throughput per-GB rate (2,700 KBPS/GB) nearly matches the 2,680 MB/s cap, so throughput cap is reached at ~993 GB." }, { "size": "ultra-high-performance-120vpus", "provider": "oci", "serviceFamily": "block-volume", "estimatedCostUsdHr": 0.163, "iopsMax": 225000, "throughputMbsMax": 2680, "iopsPerGb": 360, "throughputKbpsPerGb": 3600, "notes": "OCI Block Volume Ultra High Performance, 120 VPUs/GB. $0.0255/GB-mo base + 110 extra VPUs × $0.00225/VPU/GB-mo = $0.273/GB-mo; flat sim rate $0.163/hr (~430 GB reference). 360 IOPS/GB and 3,600 KBPS/GB; volume caps unchanged at 225,000 IOPS and 2,680 MB/s. IOPS cap saturates at ~625 GB — the most IOPS-dense UHP tier. Both caps are reachable on relatively small volumes, maximising peak performance per GB." } ] ``` Key fields for tier selection: all UHP tiers share the same absolute volume caps (225,000 IOPS, 2,680 MB/s). VPU count determines the per-GB density at which those caps are reached. Choose a higher VPU tier when volumes are small but IOPS demand is high — a 625 GB volume at 120 VPUs delivers the same peak IOPS as a 2,500 GB volume at 30 VPUs, at a higher per-GB price but with less provisioned capacity. Prefer 30 VPUs for large volumes where per-GB rate is the primary cost driver and the IOPS cap is reachable purely through volume size. --- ### x402 Pay-Per-Request API Anonymous pay-per-request access using USDC-on-Base. No API key or account required — attach an `X-PAYMENT` header and call any of the 14 metered endpoints. Use `GET /billing/x402/config` first to discover whether x402 is enabled and to read exact USDC amounts. The 14 paid call types are: `simulation_step_hybrid`, `rl_step`, `rl_batch_step`, `rl_eval_episodes`, `ai_explain`, `ai_optimize`, `ai_troubleshoot`, `ai_bottleneck` ($0.0010 each), and `chaos_run`, `chaos_batch`, `multicloud_explore`, `optimization_run`, `prediction_validate`, `prediction_optimize_thresholds` ($0.0050 each). | Method | Path | Auth | Description | |---|---|---|---| | GET | /billing/x402/config | Public | x402 configuration: enabled flag, payTo wallet address, network, USDC asset address, facilitator URL, credits-per-USDC rate, and per-call-type price table | | GET | /billing/x402/balance | Public | Credit balance for a wallet address (`?address=0x...`); returns 404 if the address has never paid for a call | | GET | /billing/x402/transactions | Public | Payment transaction history for a wallet address (`?address=0x...&limit=50`); positive delta = payment received, negative delta = call deducted | --- ## Webhook / Callback System Asynchronous notifications POSTed to agent-provided URLs on job completion. - **Supported jobs**: `analysis/optimize`, `chaos/run`, `chaos/batch`, `predictions/validate`, `predictions/optimize-thresholds`, `multi-cloud/explore`, `rl/environments` (episode completion). - **Security**: HTTPS-only destinations; SSRF protection (private IP ranges and localhost are blocked). - **Signature**: Every webhook includes an `X-Webhook-Signature` header containing an HMAC-SHA256 signature. Verify by computing `HMAC-SHA256(webhookSecret, rawBody)` and comparing with constant-time equality. - **Retry logic**: Up to 3 delivery attempts with exponential backoff (0 s, 2 s, 8 s). Each attempt has a 10-second timeout. - **Delivery tracking**: Job responses include `webhookDeliveryStatus` (`"pending"`, `"delivered"`, or `"failed"`), `webhookDeliveryAttempts`, `webhookDeliveryError`, and `webhookDeliveredAt`. - **Payload format**: JSON with `{ event, jobId, status, data, timestamp }`. The `event` field follows the pattern `".completed"` or `".failed"`. --- ## Authentication & Security Notes - All authenticated endpoints require `Authorization: Bearer ` header. - API keys are bcrypt-hashed at rest; the raw key is only shown once at issuance. - Keys support scope-based access control: `read`, `write`, `admin`. - Rate limiting is enforced per key (default: 1000 requests/hour). - Exhausting credits blocks further simulation steps (`credits_exhausted` event is fired). - Webhook URLs undergo SSRF validation; private IP ranges and DNS rebinding are blocked. --- ## Integration & Tech Stack - **AI**: OpenAI GPT-5 via Replit AI Integrations - simulation explanations, bottleneck analysis, architecture optimization suggestions, and beginner-friendly explanations. - **Payments**: Stripe - credit top-ups via Stripe Checkout; webhook handler for authoritative payment confirmation (`topup_completed` event). - **Analytics**: PostHog - product analytics, session recordings, and feature flags (no-op when key is absent). - **Database**: PostgreSQL via Drizzle ORM and Neon serverless adapter (in-memory in development). - **Frontend**: React 18, TypeScript, Vite, Wouter, TanStack Query, Shadcn/ui, Tailwind CSS. - **Backend**: Express.js, TypeScript, Node.js. --- ## WebMCP Browser Tools AI agents navigating the site in a WebMCP-enabled browser (Chrome 149+ with the `#enable-webmcp` flag or a valid Origin Trial token) can call platform actions directly via `navigator.modelContext`. The registration is a pure progressive enhancement — non-WebMCP browsers are completely unaffected. The `Permissions-Policy: webmcp=*` response header is set on all pages to opt the site in to the API. ### Registered Tools | Tool name | Description | |---|---| | `run_simulation_step` | Advance the active simulation by one tick; returns updated CPU, latency, throughput, error rate, and cost snapshot. | | `reset_simulation` | Pause the active simulation and reset traffic to zero. | | `inject_traffic_pattern` | Inject a named traffic pattern (`ramp`, `burst`, `step`, `wave`, `custom`; legacy aliases `spike`→`burst`, `sine`→`wave`, `gradual_increase`→`ramp`) into the running simulation. | | `inject_failure` | Inject a named failure type (`database_crash`, `zone_outage`, `network_latency`, `instance_kill`) into the running simulation. | | `inject_failure_create` | Create a named, scheduled failure injection (`POST /simulations/{id}/failures`): specify type (`instance_kill`, `az_outage`, `database_overload`, `network_latency`), start/end steps, and optional target resource or zone. Requires `write` scope or wallet JWT. | | `inject_failure_update` | Update an existing failure injection (`PATCH /failures/{id}`): deactivate it early (`isActive: false`) or adjust its end time. Requires `write` scope or wallet JWT. | | `inject_failure_delete` | Permanently delete a failure injection (`DELETE /failures/{id}`). Returns 204 No Content. Requires `write` scope or wallet JWT. | | `get_current_metrics` | Read the latest CPU utilization, latency percentiles (P50/P95/P99), error rate, throughput, and estimated hourly cost for the active simulation. | | `navigate_to_page` | Navigate the browser to a named platform page: `home`, `scenarios`, `billing`, `docs`, `api-reference`. | All simulation tools accept an optional `simulationId` input; when omitted they resolve the active simulation from the URL query string (`?simulation=`) or by fetching the first simulation from the API. Tools call the `/api/ui/*` REST endpoints (no API key required) and follow the same rate limits as the browser workspace. --- ## Docs & Discovery - [llms.txt](https://www.cloudworldmodel.ai/llms.txt) - Concise summary for AI tools (llmstxt.org format) - [OpenAPI spec (JSON)](https://www.cloudworldmodel.ai/api-docs/openapi.json) - Machine-readable OpenAPI 3.1 specification in JSON format (full 90-route spec) — consumable by AI coding assistants and API clients - [OpenAPI spec (YAML)](https://www.cloudworldmodel.ai/openapi.yaml) - Machine-readable OpenAPI 3.1 specification in YAML format (served from project root) - [Swagger UI](https://www.cloudworldmodel.ai/api-docs) - Interactive API explorer powered by Swagger UI - [Sitemap](https://www.cloudworldmodel.ai/sitemap.xml) - XML sitemap of all public pages - [Canvas Cloud AI](https://canvascloud.ai) - Primary product that Cloud World Model complements