oc-scale-ops — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited oc-scale-ops (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
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.
On first invocation, read `references/orchestrator.md` and follow its welcome protocol.
Assess and improve an app's ability to handle growth. Covers load testing, performance budgets, caching strategy, query optimization, CDN config, and capacity planning. Produces a scaling readiness report with a concrete upgrade path from current capacity to target capacity.
SCALE OPS COMMANDS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ASSESS
/oc-scale audit Full scaling readiness assessment
/oc-scale budget Set or audit performance budgets
/oc-scale bottleneck Identify the #1 scaling bottleneck
TEST
/oc-scale loadtest Run load test against target URL
/oc-scale benchmark Benchmark specific endpoints
OPTIMIZE
/oc-scale cache Design or audit caching strategy
/oc-scale queries Audit and optimize database queries
/oc-scale cdn CDN and edge optimization
PLAN
/oc-scale plan Capacity plan from current → target users
/oc-scale cost Cost projection at target scale
UTILITIES
/checkpoint Show checkpoint status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Type any command to begin. /oc-scale to see this again./oc-scale audit)Comprehensive evaluation of how the app handles load. Produces a readiness score and prioritized optimization list.
| Layer | Checks | Tools |
|---|---|---|
| Database | Query complexity, missing indexes, N+1 patterns, connection pooling, row counts | EXPLAIN ANALYZE, schema review |
| API | Response times, payload sizes, pagination, rate limiting, caching headers | curl timing, endpoint inventory |
| Frontend | Bundle size, code splitting, lazy loading, image optimization, core web vitals | Lighthouse, bundle analysis |
| Infrastructure | Worker limits, D1 limits, KV limits, edge caching, CDN config | CF dashboard / API |
| Architecture | Stateless design, horizontal scalability, single points of failure | Code review |
| Service | Free Tier | Paid Tier | Hard Ceiling |
|---|---|---|---|
| Workers requests | 100K/day | 10M/mo ($5) | Unlimited (pay per use) |
| Workers CPU time | 10ms/invocation | 30s/invocation | 30s |
| D1 reads | 5M/day | 25B/mo | Bound by SQLite limits |
| D1 writes | 100K/day | 50M/mo | 1 writer at a time |
| D1 database size | 500MB | 10GB | 10GB per DB |
| KV reads | 100K/day | 10M/mo | 1000 reads/sec per namespace |
| KV writes | 1K/day | 1M/mo | 1 write/sec per key |
| R2 storage | 10GB | Pay per use | Unlimited |
| Pages deployments | 500/mo | 5000/mo | Per project |
| Score | Meaning | Can Handle |
|---|---|---|
| A | Production-ready at scale | 10K+ concurrent users |
| B | Ready for moderate traffic | 1K-10K concurrent users |
| C | Works for small teams | 100-1K concurrent users |
| D | Works for personal use | 1-100 concurrent users (aidops-scale) |
| F | Has scaling blockers | Will break under real load |
# Scaling Readiness Report — [project]
## Current Profile
- Users: ~[N] (daily active)
- Requests: ~[N]/day
- Database: [size], [tables], [heaviest query]
- Infrastructure: [CF plan], [services used]
## Readiness Score: [A-F]
[One-sentence summary]
## Layer Scores
| Layer | Score | Bottleneck |
|---|---|---|
| Database | B | Missing index on sessions.user_id |
| API | C | No response caching, 4 N+1 queries |
| Frontend | A | Bundle 89KB gzipped, lazy loading active |
| Infrastructure | D | D1 free tier, 100K write limit/day |
| Architecture | B | Stateless workers, but single D1 database |
## Top 5 Bottlenecks (fix in order)
1. [Most impactful issue with fix]
2. ...
## Scaling Path: [current users] → [target users]
[What needs to change at each tier]/oc-scale budget)Define measurable limits for each performance dimension:
| Metric | Budget | Measurement |
|---|---|---|
| Time to First Byte (TTFB) | < 200ms | Server response time |
| First Contentful Paint (FCP) | < 1.5s | Browser paint |
| Largest Contentful Paint (LCP) | < 2.5s | Largest visible element |
| Cumulative Layout Shift (CLS) | < 0.1 | Visual stability |
| Interaction to Next Paint (INP) | < 200ms | Input responsiveness |
| API response time (p50) | < 100ms | Median endpoint latency |
| API response time (p95) | < 500ms | Tail latency |
| JS bundle size (gzipped) | < 150KB | Initial load |
| Total page weight | < 500KB | All resources |
| Database query time (p95) | < 50ms | Slowest queries |
# Lighthouse CI (run in CI or locally)
npx lhci autorun --collect.url="<url>" \
--assert.preset=lighthouse:recommended \
--assert.assertions.first-contentful-paint=["error",{"maxNumericValue":1500}] \
--assert.assertions.largest-contentful-paint=["error",{"maxNumericValue":2500}]
# Bundle size check
npx bundlesize --config bundlesize.config.json
# bundlesize.config.json:
# { "files": [{ "path": "dist/index.js", "maxSize": "150 kB" }] }After setting budgets, integrate into the pipeline:
/oc-audit perf checks budget compliance/oc-scale loadtest)# Install
cargo install oha 2>/dev/null || brew install oha 2>/dev/null
# Basic load test: 100 concurrent connections, 30 seconds
oha -c 100 -z 30s https://your-app.workers.dev/api/health
# With custom headers (auth)
oha -c 50 -z 30s -H "Authorization: Bearer <token>" https://your-app.workers.dev/api/data
# Target specific RPS (requests per second)
oha -c 20 --rps 100 -z 60s https://your-app.workers.dev/api/health# Install
go install github.com/rakyll/hey@latest 2>/dev/null
# 1000 requests, 50 concurrent
hey -n 1000 -c 50 https://your-app.workers.dev/api/health
# With POST body
hey -n 500 -c 20 -m POST -H "Content-Type: application/json" \
-d '{"test": true}' https://your-app.workers.dev/api/data# Simple timing
curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
https://your-app.workers.dev/api/health
# Run 20 times, get averages
for i in $(seq 1 20); do
curl -o /dev/null -s -w "%{time_total}\n" https://your-app.workers.dev/api/health
done | awk '{sum+=$1} END {print "Avg:", sum/NR, "s"}'## Load Test Results — [endpoint]
### Configuration
- Tool: oha
- Concurrency: 100
- Duration: 30s
- Target: https://oc-app.workers.dev/api/health
### Results
| Metric | Value | Budget | Status |
|---|---|---|---|
| Requests/sec | 2,340 | 1,000 | ✅ |
| p50 latency | 42ms | 100ms | ✅ |
| p95 latency | 187ms | 500ms | ✅ |
| p99 latency | 890ms | 1000ms | ✅ |
| Error rate | 0.1% | < 1% | ✅ |
| Total requests | 70,200 | — | — |
| Timeouts | 3 | 0 | ⚠️ |
### Observations
- [What happened at peak load]
- [Where latency spiked]
- [Any errors and their patterns]/oc-scale cache)Request
│
├──► CF CDN Cache (static assets, HTML if cacheable)
│ TTL: hours-days
│
├──► CF KV (app-level cache)
│ TTL: minutes-hours
│ Use for: API responses, computed values, session data
│
├──► D1 Query Cache (automatic in Workers)
│ TTL: per-request (not cross-request)
│
└──► Origin (D1 query)
No cache, always fresh| Data Type | Cache? | Where | TTL | Invalidation |
|---|---|---|---|---|
| Static assets (JS, CSS, images) | Yes | CDN | 1 year (immutable hash) | Deploy new hash |
| User-specific data | Maybe | KV | 1-5 min | On write (purge key) |
| Public list data | Yes | KV | 5-15 min | On write or TTL |
| Auth tokens | Yes | KV | Token expiry - 60s | On refresh |
| Computed aggregations | Yes | KV | 5-60 min | On underlying data change |
| Real-time data | No | — | — | — |
async function withCache<T>(
kv: KVNamespace,
key: string,
ttl: number,
fetcher: () => Promise<T>
): Promise<T> {
// Try cache first
const cached = await kv.get(key, 'json');
if (cached) return cached as T;
// Cache miss — fetch and store
const fresh = await fetcher();
await kv.put(key, JSON.stringify(fresh), { expirationTtl: ttl });
return fresh;
}
// Usage
const contacts = await withCache(env.CACHE, `contacts:${userId}`, 300, () =>
db.select().from(contacts).where(eq(contacts.userId, userId))
);// Invalidate on write
app.post('/api/contacts', async (c) => {
const contact = await createContact(c.env.DB, data);
// Purge relevant cache keys
await c.env.CACHE.delete(`contacts:${userId}`);
await c.env.CACHE.delete(`contacts:${userId}:count`);
return c.json(contact, 201);
});/oc-scale queries)-- D1: no built-in slow query log, but you can time queries in code
-- Wrap queries with timing:async function timedQuery<T>(db: D1Database, sql: string, params: any[]): Promise<{ result: T; ms: number }> {
const start = performance.now();
const result = await db.prepare(sql).bind(...params).all();
const ms = performance.now() - start;
if (ms > 50) console.warn(`Slow query (${ms.toFixed(0)}ms): ${sql.substring(0, 100)}`);
return { result: result.results as T, ms };
}| Problem | Detection | Fix |
|---|---|---|
| Missing index | Query on column without index, table > 1K rows | CREATE INDEX idx_table_col ON table(col) |
| N+1 queries | Loop with DB call inside (fetch list, then fetch detail per item) | Use JOIN or batch query |
| SELECT * | Fetching all columns when only 2-3 needed | List specific columns |
| Unbounded query | No LIMIT on list queries | Add pagination (LIMIT + OFFSET or cursor) |
| Repeated queries | Same query called multiple times per request | Cache result in request context |
| Missing compound index | WHERE on multiple columns, each indexed separately | CREATE INDEX idx_tbl_a_b ON tbl(a, b) |
-- D1 supports EXPLAIN QUERY PLAN
EXPLAIN QUERY PLAN SELECT * FROM sessions WHERE user_id = ? AND created_at > ?;
-- Look for: SCAN TABLE (bad) vs SEARCH TABLE USING INDEX (good)/oc-scale plan)## Capacity Plan: [current] → [target] users
### Current State
- DAU: [N]
- Peak concurrent: [N]
- Requests/day: [N]
- DB size: [N] MB
- Monthly cost: $[N]
### Growth Tiers
| Tier | Users | Requests/day | DB Size | Changes Needed | Monthly Cost |
|---|---|---|---|---|---|
| Current | 2 | 500 | 5 MB | None | $0 (free tier) |
| Small | 100 | 50K | 50 MB | Add indexes, KV caching | $0 (free tier) |
| Medium | 1K | 500K | 500 MB | Paid Workers, optimize queries | $5-15 |
| Large | 10K | 5M | 5 GB | Multiple D1 DBs or Postgres, CDN | $50-200 |
| Scale | 100K+ | 50M+ | 50+ GB | External Postgres, queue system, read replicas | $200+ |
### Tier Transition Checklist
When moving from [current tier] to [next tier]:
1. [ ] [Specific infrastructure change]
2. [ ] [Query optimization needed]
3. [ ] [Caching to add]
4. [ ] [Cost increase to approve]
5. [ ] [Load test to validate]{project-dir}/.checkpoints/oc-scale-ops.checkpoint.json
| Event | What to Save |
|---|---|
| Readiness audit run | Scores per layer, bottleneck list, overall grade |
| Performance budgets set | Budget values, enforcement config |
| Load test completed | Results, endpoint, concurrency, pass/fail |
| Caching strategy designed | Cache layers, TTLs, invalidation plan |
| Query optimization done | Queries optimized, before/after times |
| Capacity plan produced | Current tier, target tier, upgrade path |
| Reads from | Why |
|---|---|
| oc-stack-forge | Stack architecture → infrastructure limits |
| oc-code-auditor | Performance findings → pre-identified bottlenecks |
| oc-deploy-ops | Current deployment config → infrastructure baseline |
| oc-integrations-engineer | API rate limits → external constraints |
| Read by | Why |
|---|---|
| oc-deploy-ops | Readiness score → deploy confidence at scale |
| oc-code-auditor | Performance budgets → /oc-audit perf thresholds |
| oc-app-architect | Cost projections → spec cost estimates |
Scaling work is advisory — recommendations the engineering team will act on over weeks. v1.2 makes those recommendations discoverable + ownable in the PM tool. See oc-integrations-engineer for the canonical PM-MCP patterns.
After every /oc-scale audit or /oc-scale loadtest, post a structured summary on the linked PM ticket:
Scale audit: Readiness {READY / WATCH / RED}.
Load profile: {N concurrent users / {req/sec} sustained}
SLO compliance: p95 {Xms / target Yms} · p99 {Xms / target Yms} · err {X% / target Y%}
Top three bottlenecks (by headroom × business-impact):
1. {component} — {one-line finding}
...
Cost projection: ~${USD/month} at {target-scale}
Full report: .checkpoints/oc-scale-ops.checkpoint.jsonFor every finding tagged HIGH or CRITICAL on the readiness scale:
issue_type: bug if it's a current pain; chore if it's ascaling-prep concern.
scaling, severity:<level>, area:<component>..opchain/pm.yaml remediation_owners.infra or.backend based on finding type.
/oc-scale capacity produces a 12-month capacity projection. The output is uploaded as a comment with the projection table + a calendar-keyed reminder ticket scheduled for the next review window (default 90 days).
When /oc-scale cost finds a > 30% cost-reduction opportunity, file a sub-ticket with the projected savings + the change required. Cost recommendations smaller than that stay in the report only — not worth the PM noise.
/oc-scale sync-pm later.
the run completes; never post partial results.
you think it is.
Caching reads buys the most headroom with the least complexity.
tier handles everything. Don't migrate to Postgres speculatively.
CI, forget about them until they break.
adding a CDN won't help. Fix the actual constraint.
you don't pay for capacity you don't use. Build the optimization, deploy it, and let usage determine cost.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.