autoscaling-capacity — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited autoscaling-capacity (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Deep skill for scaling and resource optimization. Everything scaling lives in one block — spec.defaultOptions.autoscaling (with capacityAI beside it); spec.localOptions[] overrides it per location. The platform keeps the chosen metric near but below target. For workload types, production defaults, and the spec shape, start with the `workload` skill.
| Metric | Scales on | Types | Notes |
|---|---|---|---|
concurrency | avg in-flight requests per replica | serverless only (its default) | pair with maxConcurrency for a hard per-replica cap |
rps | requests per second per replica | all three | consistent-response-time HTTP |
cpu | % of allocated CPU | all three (stateful default) | target ≤ 100; conflicts with Capacity AI (below) |
memory | % of allocated memory | all three | target ≤ 100 |
latency | response time in ms at metricPercentile | standard / stateful | p50 (default) / p75 / p99; target is ms, not % |
multi[] | several metrics; highest replica count wins | standard / stateful | entries from cpu / memory / rps only, each at most once; replaces metric and top-level target |
keda | external / event-driven triggers | standard / stateful | GVC must enable KEDA first; target is rejected |
disabled | nothing — fixed at minScale | all | realized as min = max |
If metric is omitted, serverless defaults to concurrency and stateful to cpu. Standard is the trap: with Capacity AI on (its default) an omitted metric resolves to disabled — min = max, no autoscaling — so always name the metric on a standard workload that must scale. A metric invalid for the workload type is rejected (e.g. concurrency on standard).
The metric constrains the type — decide them together. Type is chosen at creation and is immutable, so a metric-type mismatch is a type problem, not a metric problem. The most common case: concurrency-style scaling on a standard workload — the fix is to create the workload as serverless (concurrency lives only there) or use `rps` on standard (the closest equivalent), not to retry with the same pairing.
Set with mcp__cpln__create_workload / mcp__cpln__update_workload, then verify with mcp__cpln__list_deployments. All fields:
spec:
defaultOptions:
autoscaling:
metric: rps
target: 100 # default 95; integer 1-20000; ≤100 for cpu/memory; ms for latency
minScale: 2 # default 1; must be ≤ maxScale; 0 = scale-to-zero (rules below)
maxScale: 10 # default 5; no schema maximum
scaleToZeroDelay: 300 # 30-3600s, default 300
maxConcurrency: 0 # serverless only; 0-30000, default 0 = unlimited (excess queues)
metricPercentile: p99 # latency only: p50 (default) / p75 / p99
capacityAI: truespec.localOptions[] (same fields + location) via mcp__cpln__configure_workload_local_options (full profile), the only MCP tool that sets capacityAIUpdateMinutes or multiZone; it replaces the full list. Both also exist on spec.defaultOptions, reachable with cpln apply.autoscaling:
minScale: 2
maxScale: 10
multi:
- metric: cpu
target: 80
- metric: memory
target: 80Each entry is evaluated independently; the highest replica count wins. Only cpu / memory / rps, each at most once; targets go inside the entries (metric/target at the top level are rejected alongside multi). With multi, Capacity AI defaults to off.
metric: keda (anything else is rejected); cron never. Serverless reaches zero with concurrency or rps; cpu and memory ride an HPA that never drops to zero. The first request after idle pays a cold start.1. Enable on the GVC first — mcp__cpln__update_gvc:
spec:
keda:
enabled: true # default false
identityLink: //gvc/GVC/identity/NAME # optional: cloud/network access for the KEDA operator
secrets: [//secret/NAME] # optional: each becomes a TriggerAuthentication named after the secret2. Set the workload — metric: keda plus raw KEDA trigger specs (passed through as-is):
autoscaling:
metric: keda # target is rejected with keda
minScale: 0 # maps to KEDA minReplicaCount — this is how standard/stateful scale to zero
maxScale: 10
keda:
triggers:
- type: redis
metadata:
address: my-redis.my-gvc.cpln.local:6379
queueLength: '5'
passwordFromEnv: REDIS_PASSWORDauthenticationRef.name (the TriggerAuthentication is named after the secret).internal.inboundAllowWorkload: [cpln://internal/keda].keda.advanced.scalingModifiers (custom formulas), fallback, pollingInterval, cooldownPeriod.type: prometheus with serverAddress: https://metrics.cpln.io:443/metrics/org/ORG, a query (PromQL), threshold, and customHeaders: Authorization=Bearer SERVICE_ACCOUNT_TOKEN (service account needs readMetrics). Before wiring any trigger, confirm the signal resolves: mcp__cpln__list_metrics for real names/labels, then mcp__cpln__query_metrics to run the PromQL — a never-resolving signal pins the workload at minScale. Custom app metrics come from the container metrics block (see metrics-observability).Right-sizes each container's reserved resources (what you're billed for) from usage history, between the minCpu/minMemory floor and the cpu/memory ceiling. Every workload type supports it. Standard, serverless, and cron enable it by default.
spec:
containers:
- name: app
cpu: '1000m' # ceiling (and the fixed allocation when Capacity AI is off)
memory: '1Gi' # ceiling
minCpu: '100m' # floor
minMemory: '256Mi' # floor
defaultOptions:
capacityAI: truecpu or multi, it silently defaults to off.capacityAIUpdateMinutes (min 2 — via localOptions or cpln apply; not on create/update tools).workload skill. minCpu and minMemory never exceed cpu and memory.cpu/memory are the fixed allocation and minCpu/minMemory are ignored — except on stateful, where minCpu/minMemory become the static reserved request and cpu/memory stay the burst ceiling.nvidia model t4 (quantity up to 4) or a10g (exactly 1); strict per-model CPU/memory minimums — fetch exact numbers with mcp__cpln__get_resource_schema (kind: workload).minCpu) directly lowers cost.| Symptom | Check |
|---|---|
| Not scaling up | Does the signal exist? mcp__cpln__list_metrics then mcp__cpln__query_metrics; check maxScale; check replica readiness via mcp__cpln__list_deployments |
| Not scaling down | Standard/stateful stabilization window = scaleToZeroDelay (default 300s); check minScale |
| Scale-to-zero not happening | Serverless needs concurrency/rps; standard/stateful need metric: keda; check scaleToZeroDelay |
| KEDA not triggering | KEDA enabled on the GVC? Trigger auth secret listed in gvc.spec.keda.secrets? Source firewall allows cpln://internal/keda? |
| Capacity AI not adjusting | Check the stored spec.defaultOptions.capacityAI; off with metric: cpu or multi; rejected with GPUs; a recent spec change pauses it; capacityAIUpdateMinutes throttle; on cron it only lands at the next execution |
Replicas stuck at minScale | The scaling metric never resolves — verify the PromQL/trigger returns data |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.