一键导入
arib-check-perf
Check | Performance audit - N+1 queries, bundle size, latency budgets, memory leaks, caching gaps
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Check | Performance audit - N+1 queries, bundle size, latency budgets, memory leaks, caching gaps
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | arib-check-perf |
| argument-hint | <scope> |
| description | Check | Performance audit - N+1 queries, bundle size, latency budgets, memory leaks, caching gaps |
Perform a comprehensive performance audit of the codebase to detect N+1 queries, oversized bundles, missing pagination, memory leaks, caching gaps, and performance budget violations.
User types /arib-check-perf [scope]
Examples:
/arib-check-perf - Full system performance audit/arib-check-perf api - Backend API endpoints only/arib-check-perf frontend - Frontend bundle and Web Vitals only/arib-check-perf /api/orders - Specific endpoint/arib-check-perf database - Database query analysis onlyPerformance degradation compounds: one N+1 query multiplied by pagination can turn seconds into minutes. This audit detects the most common and impactful bottlenecks before users experience them. Each finding includes severity, impact (latency, bundle size, memory), and exact file location for remediation.
Read .claude/agents/performance.md and follow the 7-step protocol.
Sequelize (Node.js):
// ANTI-PATTERN: N+1 query
const users = await User.findAll(); // 1 query: SELECT * FROM users
for (const user of users) {
user.posts = await Post.findAll({ where: { userId: user.id } }); // N more queries
}
// FIXED: Eager loading
const users = await User.findAll({
include: [{ association: 'posts', attributes: ['id', 'title'] }]
});
Prisma (Node.js):
// ANTI-PATTERN: N+1
const users = await prisma.user.findMany();
const userPosts = await Promise.all(
users.map(u => prisma.post.findMany({ where: { userId: u.id } }))
);
// FIXED: Eager loading
const users = await prisma.user.findMany({
include: { posts: true }
});
TypeORM (Node.js/Python):
// ANTI-PATTERN
const users = await User.find(); // 1 query
users.forEach(u => u.posts); // Access triggers N more queries (lazy loading)
// FIXED: Eager loading
const users = await User.find({ relations: ['posts'] });
Django (Python):
# ANTI-PATTERN: N+1
users = User.objects.all() # 1 query
for user in users:
print(user.posts.all()) # N more queries
# FIXED: select_related / prefetch_related
users = User.objects.prefetch_related('posts')
.all() or .find() followed by attribute access in loops| App Type | API Response Limit | Reasoning |
|---|---|---|
| Mobile API | 50-100 KB | Over cellular networks, 3G common |
| Public API | 100-200 KB | Unknown network, clients pay per byte |
| Internal Dashboard | 500 KB | Trusted network, single product |
| Admin Tools | 1 MB | Low volume, premium features |
| File Download | 10+ MB | Expected, user initiated |
/graphql, /users, /reports, /searchJSON.stringify(response).lengthIs this a route or major feature?
├─ YES → Lazy load (React.lazy, dynamic imports)
│ Route: lazy(() => import('./pages/Dashboard'))
│ Component: const Modal = lazy(() => import('./Modal'))
│
└─ NO → Keep in main bundle if:
• Always used on page load
• Small (< 50 KB minified)
• Critical for initial render
| Pattern | Detection | Fix |
|---|---|---|
| Full lodash import | import _ from 'lodash' | Use tree-shaking: import { debounce } from 'lodash-es' |
| Moment.js | Any import moment | Replace with date-fns or dayjs (5-20x smaller) |
| Unused CSS frameworks | Bootstrap 5 = 200+ KB | Use utility-first (Tailwind) or import only used components |
| Multiple charting libs | Chart.js + Recharts | Pick one, tree-shake unused features |
| Polyfills | Babel includes 200+ KB | Target modern browsers, conditional polyfills |
npm run build --analyze or use webpack-bundle-analyzer| Type | Mobile | Desktop | Format |
|---|---|---|---|
| Hero image | < 200 KB | < 500 KB | WebP + JPEG fallback |
| Thumbnail | < 50 KB | < 100 KB | WebP or optimized JPEG |
| Icon | < 5 KB | < 10 KB | SVG (optimized) or PNG |
| Background | < 300 KB | < 1 MB | WebP or JPEG |
Is this column in a WHERE clause?
├─ YES → Add index (single or composite)
│
Is this a foreign key?
├─ YES → Add index (join performance)
│
Is this in an ORDER BY?
├─ YES → Add index (sort performance)
│
Is this searched frequently?
├─ YES → Consider index (trade write slowdown for read speed)
Pool size = (concurrent_requests × avg_query_duration_seconds) / 1
Example: (50 req/s × 0.1s) / 1 = min 5, recommend 10-20
Maximum: 100 (diminishing returns, more memory per connection)
| Pattern | Detection | Fix |
|---|---|---|
| Event listeners | .addEventListener() without .removeEventListener() | Always pair with cleanup in unmount/destroy |
| setInterval | setInterval() without clearInterval() | Store ID: id = setInterval(), clear in cleanup |
| Streams | .pipe() without close handler | Add: stream.on('end', () => stream.destroy()) |
| Subscriptions | RxJS subscribe() without unsubscribe() | Use takeUntil() or unsubscribe in cleanup |
| Collections | array.push() in loop without bounds | Add: if (array.length > MAX) array.shift() |
| Timers | setTimeout() in loop | Batch with clearTimeout or use debounce |
Is this endpoint read-heavy (mostly GET)?
└─ YES
├─ Does data change frequently (< 1 hour)?
│ ├─ NO → Cache aggressive: TTL 24h
│ └─ YES → Cache moderate: TTL 5-60 min
├─ Is this user-specific data (auth tokens, preferences)?
│ └─ YES → Cache per-user (private cache)
└─ Is this global data (products, settings)?
└─ YES → Cache globally (shared cache)
Is this write-heavy?
└─ YES → Cache on write, not read
├─ Cache invalidation: delete on POST/PUT/DELETE
└─ Cache warming: precompute expensive calculations
Endpoint: GET /api/products
Data freshness: Products rarely change (1-2x per day)
Request volume: 10,000 req/min
Cache type: Redis (distributed) or in-memory (single server)
Cache strategy:
- TTL: 1 hour (3600 seconds)
- Invalidation: Delete cache on product update/delete
- Warming: Load on server start or first request
- Fallback: If Redis down, compute fresh or return stale
Expected impact:
- Requests per minute to DB: 10,000 → 50 (if 1% hit rate)
- Latency: 50ms → 5ms (10x improvement)
- DB load: 600 queries/min → 3 queries/min (200x reduction)
Produce the Performance Audit Report with:
performance_budget:
api:
p95_latency_ms: 200
p99_latency_ms: 500
max_response_kb: 100
frontend:
bundle_size_kb: 300
core_web_vitals:
lcp_ms: 2500
fid_ms: 100
cls: 0.1
database:
p95_query_ms: 100
connections: 20
slow_query_threshold_ms: 500
memory:
node_process_mb: 300
browser_tab_mb: 200
[endpoint]_[user_id] or mark private/arib-check-services - Infrastructure latency/arib-check-reality - Verify data is real (not mock) before profiling/arib-dev-debug - Investigate specific slowness hypothesisMemory | Code-graph subsystem — a native lightweight IMPORT graph (which file imports which, god-node candidates) built with ripgrep/grep, so a large monorepo can be navigated by structure instead of re-grepping every session. build/refresh/query. Honest scope: structural import graph, NOT semantic (no call-graph/type resolution); no Graphify dependency. Loads ON DEMAND only (zero always-on tokens). ADR-034.
Dev | Over-engineering review — reads a diff/module and returns a delete-list of bloat (single-use abstractions, premature generalization, speculative config, dead options) WITHOUT stripping legitimate structure. Advisory: returns recommendations, never auto-deletes. The on-demand companion to the ponytail-lite tripwire hook. Authored natively (no Ponytail dependency). ADR-033.
Wave | Pre-wave requirement lock — Act 1 derives the requirements from the codebase + memory (an honest grill, not guesswork), Act 2 hands the locked plan to an independent model (Codex) to tear apart until sign-off. Produces waves/<id>/PLAN.md + PLAN-REVIEW-LOG.md. Auto-chained idempotently from /arib-wave-start. If Act 2 can't run (no Codex), the wave proceeds but HOLDS MERGE for a human. Absorbs grill-me-codex (ADR-032).
Wave | Start a multi-session delivery wave — branch, plan, parallel architect+planner
Engine | Command the engineering team to deliver a known goal — dispatches the engineer-manager to decompose → dispatch specialists (parallel where safe) → integrate → reconcile (verification-agent) → merge gate. Scales its own reach: runs inline for a bounded goal, escalates to a parallel Workflow for a broad one, and paces under /loop for a multi-turn campaign — only when it needs to. Use when a goal needs a coordinated TEAM, not one specialist. Sibling of /arib-engine: the engine DISCOVERS its own backlog; /arib-build EXECUTES a goal you hand it.
Stack | NestJS architecture & patterns reference — modules/providers/DI, DTO+validation, guards/interceptors/pipes/filters, config, async lifecycle, testing, and the security + performance pitfalls that bite at scale. Use when building or reviewing a NestJS backend. Composes with security-auditor (OWASP), database-guardian (TypeORM/Prisma migrations), and performance (N+1). Authored natively (the ECC graft was unsourceable; this is CCM's own, MIT).