@rune-kit/rune 2.3.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +395 -389
- package/compiler/__tests__/tier-override.test.js +158 -0
- package/compiler/adapters/antigravity.js +3 -8
- package/compiler/adapters/codex.js +3 -8
- package/compiler/adapters/cursor.js +3 -8
- package/compiler/adapters/generic.js +3 -8
- package/compiler/adapters/openclaw.js +4 -9
- package/compiler/adapters/opencode.js +3 -8
- package/compiler/adapters/windsurf.js +3 -8
- package/compiler/bin/rune.js +34 -1
- package/compiler/emitter.js +94 -5
- package/compiler/transforms/branding.js +10 -3
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/VISION.md +3 -3
- package/docs/guides/index.html +14 -14
- package/docs/index.html +7 -7
- package/docs/skills/index.html +832 -832
- package/extensions/ai-ml/PACK.md +7 -0
- package/extensions/content/PACK.md +7 -0
- package/extensions/mobile/PACK.md +9 -9
- package/extensions/zalo/PACK.md +9 -0
- package/package.json +2 -2
- package/skills/audit/SKILL.md +526 -529
- package/skills/ba/SKILL.md +349 -351
- package/skills/completion-gate/SKILL.md +260 -263
- package/skills/context-engine/SKILL.md +0 -6
- package/skills/cook/SKILL.md +2 -11
- package/skills/db/SKILL.md +5 -1
- package/skills/db/references/scaling-reference.md +271 -0
- package/skills/debug/SKILL.md +392 -394
- package/skills/deploy/references/post-deploy-integration.md +192 -0
- package/skills/fix/SKILL.md +281 -282
- package/skills/onboard/SKILL.md +0 -4
- package/skills/plan/references/completeness-scoring.md +0 -1
- package/skills/plan/references/outcome-block.md +0 -1
- package/skills/plan/references/workflow-registry.md +0 -1
- package/skills/preflight/SKILL.md +360 -365
- package/skills/rescue/SKILL.md +1 -0
- package/skills/research/SKILL.md +149 -150
- package/skills/review/SKILL.md +489 -495
- package/skills/sentinel/SKILL.md +0 -11
- package/skills/sentinel/references/destructive-commands.md +0 -1
- package/skills/sentinel/references/skill-content-guard.md +0 -1
- package/skills/session-bridge/SKILL.md +0 -4
- package/skills/skill-forge/SKILL.md +5 -1
- package/skills/skill-forge/references/claude-skill-reference.md +182 -0
- package/skills/skill-router/{SKILL.md → skill.md} +446 -397
- package/skills/team/SKILL.md +1 -2
- package/skills/test/SKILL.md +585 -593
- package/skills/watchdog/references/webhook-health-checks.md +243 -0
package/skills/db/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: db
|
|
|
3
3
|
description: Database workflow specialist. Generates migration files with rollback scripts, detects breaking schema changes, and validates query parameterization.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.2.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: sonnet
|
|
9
9
|
group: development
|
|
@@ -35,6 +35,10 @@ Database workflow specialist. Handles the parts of database work that cause prod
|
|
|
35
35
|
- `deploy` (L2): pre-deploy migration safety check
|
|
36
36
|
- `audit` (L2): database health dimension
|
|
37
37
|
|
|
38
|
+
## References
|
|
39
|
+
|
|
40
|
+
- `references/scaling-reference.md` — Index strategies, query optimization, N+1 prevention, connection pooling, read replicas, partitioning, sharding, denormalization. Load when scaling, performance, or indexing context detected.
|
|
41
|
+
|
|
38
42
|
## Executable Steps
|
|
39
43
|
|
|
40
44
|
### Step 1 — Discovery
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Database Scaling Reference
|
|
2
|
+
|
|
3
|
+
> Loaded by `db` skill when scaling, indexing, or performance optimization context is detected.
|
|
4
|
+
> Source patterns: production-proven PostgreSQL scaling strategies.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Indexing Strategy
|
|
9
|
+
|
|
10
|
+
### Index Type Selection
|
|
11
|
+
|
|
12
|
+
| Type | Use Case | Example |
|
|
13
|
+
|------|----------|---------|
|
|
14
|
+
| **B-tree** (default) | Equality, range, sorting | `WHERE id = 1`, `ORDER BY date` |
|
|
15
|
+
| **GIN** | Arrays, JSONB, full-text search | `WHERE tags @> ARRAY['a']` |
|
|
16
|
+
| **GiST** | Geometric, spatial, nearest-neighbor | PostGIS, `ORDER BY location <->` |
|
|
17
|
+
| **BRIN** | Large tables with natural ordering | Time-series > 100GB |
|
|
18
|
+
|
|
19
|
+
### Compound Index Rules
|
|
20
|
+
|
|
21
|
+
Order columns: **equality → range → sort**
|
|
22
|
+
|
|
23
|
+
```sql
|
|
24
|
+
-- Query: WHERE customer_id = X AND status IN (...) AND created_at > Y ORDER BY id
|
|
25
|
+
CREATE INDEX idx_orders ON orders(customer_id, status, created_at, id);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Partial Indexes (index what you query)
|
|
29
|
+
|
|
30
|
+
```sql
|
|
31
|
+
-- Only index active users (90% smaller, 90% faster writes)
|
|
32
|
+
CREATE INDEX idx_active_users ON users(email) WHERE status = 'active';
|
|
33
|
+
|
|
34
|
+
-- Only index pending orders
|
|
35
|
+
CREATE INDEX idx_pending_orders ON orders(customer_id) WHERE status = 'pending';
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Covering Indexes (avoid heap lookups)
|
|
39
|
+
|
|
40
|
+
```sql
|
|
41
|
+
-- Query only needs total and date — include them in index
|
|
42
|
+
CREATE INDEX idx_orders_covering ON orders(customer_id)
|
|
43
|
+
INCLUDE (total, created_at);
|
|
44
|
+
|
|
45
|
+
-- Index-only scan — no heap access needed
|
|
46
|
+
SELECT total, created_at FROM orders WHERE customer_id = 123;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Index Anti-Patterns
|
|
50
|
+
|
|
51
|
+
- Indexing every column (slows writes, wastes storage)
|
|
52
|
+
- Indexing low-cardinality columns alone (status with 3 values → useless)
|
|
53
|
+
- Missing indexes on foreign keys (kills JOIN performance)
|
|
54
|
+
- Unused indexes (check `pg_stat_user_indexes` for `idx_scan = 0`)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Query Optimization
|
|
59
|
+
|
|
60
|
+
### EXPLAIN ANALYZE — Always Profile
|
|
61
|
+
|
|
62
|
+
```sql
|
|
63
|
+
EXPLAIN (ANALYZE, BUFFERS, TIMING ON)
|
|
64
|
+
SELECT * FROM orders WHERE customer_id = 123 AND created_at > NOW() - INTERVAL '30d';
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Red flags in output:**
|
|
68
|
+
- `Seq Scan` on large table → missing index
|
|
69
|
+
- `Filter` removes most rows → index should be more selective
|
|
70
|
+
- `Sort` with high cost → add index that matches ORDER BY
|
|
71
|
+
- `Nested Loop` with large outer table → consider hash/merge join
|
|
72
|
+
|
|
73
|
+
### pg_stat_statements — Find Problem Queries
|
|
74
|
+
|
|
75
|
+
```sql
|
|
76
|
+
-- Top 10 slowest queries by total time
|
|
77
|
+
SELECT query, calls, total_exec_time / 1000 AS total_sec,
|
|
78
|
+
mean_exec_time AS avg_ms,
|
|
79
|
+
100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0) AS cache_pct
|
|
80
|
+
FROM pg_stat_statements
|
|
81
|
+
ORDER BY total_exec_time DESC LIMIT 10;
|
|
82
|
+
|
|
83
|
+
-- N+1 detector: queries called many times with low individual cost
|
|
84
|
+
SELECT query, calls, mean_exec_time AS avg_ms
|
|
85
|
+
FROM pg_stat_statements
|
|
86
|
+
WHERE calls > 1000 AND mean_exec_time < 5
|
|
87
|
+
ORDER BY calls DESC LIMIT 10;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## N+1 Query Prevention
|
|
93
|
+
|
|
94
|
+
### Prisma
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// BAD: 1 + N queries
|
|
98
|
+
const users = await prisma.user.findMany();
|
|
99
|
+
for (const u of users) {
|
|
100
|
+
u.posts = await prisma.post.findMany({ where: { authorId: u.id } });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// GOOD: 2 queries (parallel fetch)
|
|
104
|
+
const users = await prisma.user.findMany({ include: { posts: true } });
|
|
105
|
+
|
|
106
|
+
// GOOD: Single query (database JOIN)
|
|
107
|
+
const users = await prisma.user.findMany({
|
|
108
|
+
relationLoadStrategy: 'join',
|
|
109
|
+
include: { posts: { select: { id: true, title: true } } }
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Drizzle (no N+1 by design)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const results = await db.select().from(users)
|
|
117
|
+
.leftJoin(posts, eq(users.id, posts.userId));
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Detection
|
|
121
|
+
|
|
122
|
+
Enable query logging — look for **query count = 1 + N** where N = row count.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// Prisma query logging
|
|
126
|
+
const prisma = new PrismaClient({ log: [{ emit: 'event', level: 'query' }] });
|
|
127
|
+
prisma.$on('query', (e) => {
|
|
128
|
+
if (e.duration > 100) console.warn(`SLOW: ${e.duration}ms — ${e.query}`);
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Connection Pooling
|
|
135
|
+
|
|
136
|
+
### Sizing Formula
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
pool_size = (CPU cores × 2) + effective_spindle_count
|
|
140
|
+
|
|
141
|
+
4-core → 9 connections
|
|
142
|
+
8-core → 17 connections
|
|
143
|
+
16-core → 33 connections
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### PgBouncer Configuration
|
|
147
|
+
|
|
148
|
+
```ini
|
|
149
|
+
[pgbouncer]
|
|
150
|
+
pool_mode = transaction # Release after each transaction
|
|
151
|
+
default_pool_size = 25 # Per database/user pair
|
|
152
|
+
min_pool_size = 10 # Keep warm
|
|
153
|
+
reserve_pool_size = 5 # Overflow buffer
|
|
154
|
+
max_client_connections = 1000 # Total client limit
|
|
155
|
+
server_idle_timeout = 600 # Close idle server connections (10min)
|
|
156
|
+
query_wait_timeout = 120 # Max wait for available connection
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Warning signs:** Pool utilization > 80%, rising wait times, connection timeouts.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Read Replicas
|
|
164
|
+
|
|
165
|
+
### When to Add
|
|
166
|
+
|
|
167
|
+
- Read:write ratio exceeds **10:1**
|
|
168
|
+
- Primary CPU consistently > 70% from read queries
|
|
169
|
+
- Analytics queries competing with transactional reads
|
|
170
|
+
|
|
171
|
+
### Routing Pattern
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const primaryPool = new Pool({ host: 'primary.db.com' });
|
|
175
|
+
const replicaPool = new Pool({ host: 'replica.db.com' });
|
|
176
|
+
|
|
177
|
+
async function query(sql: string, params: unknown[], opts?: { write?: boolean }) {
|
|
178
|
+
const pool = opts?.write ? primaryPool : replicaPool;
|
|
179
|
+
return pool.query(sql, params);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Replication Lag
|
|
184
|
+
|
|
185
|
+
- Typical: 5-50ms for well-tuned async replication
|
|
186
|
+
- **Read-your-writes consistency**: After a write, read from primary for that user's session
|
|
187
|
+
- **Analytics queries**: Always safe on replicas (stale data acceptable)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Partitioning
|
|
192
|
+
|
|
193
|
+
### When to Partition
|
|
194
|
+
|
|
195
|
+
- Table exceeds **100GB** or **100M+ rows**
|
|
196
|
+
- Queries always filter on a specific column (date, tenant)
|
|
197
|
+
- Need fast deletion of old data (`DROP` partition vs `DELETE`)
|
|
198
|
+
|
|
199
|
+
### Range Partitioning (time-series)
|
|
200
|
+
|
|
201
|
+
```sql
|
|
202
|
+
CREATE TABLE events (
|
|
203
|
+
id BIGSERIAL, created_at TIMESTAMPTZ NOT NULL, data JSONB
|
|
204
|
+
) PARTITION BY RANGE (created_at);
|
|
205
|
+
|
|
206
|
+
CREATE TABLE events_2025_01 PARTITION OF events
|
|
207
|
+
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
|
|
208
|
+
|
|
209
|
+
-- Delete old data instantly
|
|
210
|
+
DROP TABLE events_2024_01; -- 0.01s vs DELETE minutes
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Hash Partitioning (even distribution)
|
|
214
|
+
|
|
215
|
+
```sql
|
|
216
|
+
CREATE TABLE orders (id BIGSERIAL, customer_id INT, data JSONB)
|
|
217
|
+
PARTITION BY HASH (customer_id);
|
|
218
|
+
|
|
219
|
+
CREATE TABLE orders_0 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 0);
|
|
220
|
+
CREATE TABLE orders_1 PARTITION OF orders FOR VALUES WITH (MODULUS 4, REMAINDER 1);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Rule:** Keep partition count under 500 — query planning overhead grows with partition count.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Sharding Decision Matrix
|
|
228
|
+
|
|
229
|
+
### When to Shard (Last Resort)
|
|
230
|
+
|
|
231
|
+
| Strategy | Pros | Cons |
|
|
232
|
+
|----------|------|------|
|
|
233
|
+
| **Hash-based** | Even distribution | No range queries on shard key |
|
|
234
|
+
| **Range-based** | Range queries work | Hot shards if distribution skewed |
|
|
235
|
+
| **Tenant-based** | Strong isolation | Uneven if tenants vary in size |
|
|
236
|
+
|
|
237
|
+
### Before Sharding, Try These First
|
|
238
|
+
|
|
239
|
+
1. Add proper indexes
|
|
240
|
+
2. Fix N+1 queries
|
|
241
|
+
3. Add read replicas
|
|
242
|
+
4. Add caching layer
|
|
243
|
+
5. Partition large tables
|
|
244
|
+
6. Vertical scaling (bigger instance)
|
|
245
|
+
7. Archive old data
|
|
246
|
+
8. Optimize queries with EXPLAIN ANALYZE
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Denormalization Decision Matrix
|
|
251
|
+
|
|
252
|
+
| Scenario | Keep Normalized | Denormalize |
|
|
253
|
+
|----------|----------------|-------------|
|
|
254
|
+
| High write volume | Yes | No |
|
|
255
|
+
| High read volume, slow joins | No | Yes |
|
|
256
|
+
| Data consistency critical | Yes | No |
|
|
257
|
+
| Analytics / reporting | No | Yes (materialized views) |
|
|
258
|
+
|
|
259
|
+
### Materialized Views
|
|
260
|
+
|
|
261
|
+
```sql
|
|
262
|
+
CREATE MATERIALIZED VIEW order_stats AS
|
|
263
|
+
SELECT customer_id, COUNT(*) AS order_count, SUM(total) AS total_spent
|
|
264
|
+
FROM orders GROUP BY customer_id;
|
|
265
|
+
|
|
266
|
+
-- Refresh periodically (CONCURRENTLY allows reads during refresh)
|
|
267
|
+
REFRESH MATERIALIZED VIEW CONCURRENTLY order_stats;
|
|
268
|
+
CREATE UNIQUE INDEX ON order_stats(customer_id);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Rule:** Start normalized. Denormalize specific queries only when EXPLAIN shows expensive joins that caching can't solve.
|