@kenkaiiii/ggcoder 5.45.0 → 5.46.1
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 +3 -1
- package/assets/skills/durable/SKILL.md +111 -0
- package/assets/skills/durable/references/backups-and-runtime.md +86 -0
- package/assets/skills/durable/references/migrations-and-schema.md +79 -0
- package/assets/skills/lean/SKILL.md +110 -0
- package/assets/skills/lean/references/memory-and-processes.md +98 -0
- package/assets/skills/lean/references/playbooks.md +107 -0
- package/dist/core/skills.js +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/tools/skill.js +1 -0
- package/dist/tools/skill.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -204,13 +204,15 @@ Reusable behaviors across projects. Drop `.md` files in:
|
|
|
204
204
|
|
|
205
205
|
They get loaded into the system prompt automatically. The agent knows what it can do without you explaining it each session. <kbd>Ctrl+S</kbd> opens a pane to browse and toggle them.
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
Five ship built in, and route themselves when the work matches:
|
|
208
208
|
|
|
209
209
|
| Skill | Fires on |
|
|
210
210
|
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
211
211
|
| `bulletproof` | Code an attacker will reach — auth, untrusted input, secrets, dependencies, CI/release, agent/MCP tool surfaces — and "is this safe to ship" reviews. Works on any target: web, API, CLI, desktop, mobile, embedded, contracts, ML. |
|
|
212
212
|
| `compliance-guard` | Legal exposure — personal data, payments, UGC, email/SMS, minors, or a licensed/regulated feature. |
|
|
213
|
+
| `durable` | User data must not be lost — first database/table, migrations, backfills/imports, destructive operations, backups and recovery; any store (Postgres, MySQL, SQLite, Mongo, serverless). |
|
|
213
214
|
| `evidence-led-ui` | Broad or design-sensitive UI work — new screens, redesigns, design systems, accessibility passes. |
|
|
215
|
+
| `lean` | Speed and resource efficiency — slow loading/startup, jank, high CPU, memory leaks and hogging, zombie/orphan processes, bundle bloat, dead code/styles, Core Web Vitals; while building anything that should stay fast, or a perf pass on an existing project. Any stack: web, backend, Electron, Tauri, mobile, native, game, ML. |
|
|
214
216
|
|
|
215
217
|
---
|
|
216
218
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: durable
|
|
3
|
+
description: Use when user data must not be lost or corrupted — creating the first database/table/schema, writing migrations, backfilling or importing data, any destructive operation (delete, drop, truncate, overwrite), setting up backups or recovery, or moving data between systems; and for "is my data safe", "will I lose my data", "back up my app" checks on existing projects. Any store — SQL (Postgres, MySQL, SQLite), document (Mongo, Firestore), serverless (Supabase, Neon, Turso), files, queues. Do NOT use for query speed or connection-pool sizing (that is lean), access control over data (that is bulletproof), or privacy/legal deletion regimes (that is compliance-guard).
|
|
4
|
+
license: Data-durability engineering guidance, not a DBA certification. Sources and snapshot date are recorded at the foot of each reference file.
|
|
5
|
+
compatibility: Snapshot dated 17 August 2026. Version behaviors (fast-path ALTERs, pooler modes, tool flags) decay — re-verify with web access before asserting them as current.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Durable
|
|
9
|
+
|
|
10
|
+
Make user data survive everything: bad migrations, crashed writes, retried webhooks, full disks, dead servers, and the 3am `DELETE` without a `WHERE`. Built for the reality that users forgive slow and ugly; they do not forgive gone.
|
|
11
|
+
|
|
12
|
+
**This skill is on from the first table.** The default mode is the inline gate below — every schema change, import, and destructive path gets the durable treatment as it is written. The full pass is for existing projects and "is my data safe" checks.
|
|
13
|
+
|
|
14
|
+
## Governing rules
|
|
15
|
+
|
|
16
|
+
1. **The database is the last line of defense, not the app.** Constraints, foreign keys, uniqueness, and NOT NULL live in the store where enforcement cannot be bypassed. App-level validation is UX, not integrity — a bug, a script, or a direct SQL session walks right past it.
|
|
17
|
+
2. **Destructive operations are guilty until proven guarded.** Any `DROP`, `TRUNCATE`, `DELETE`, `UPDATE` without a `WHERE`, or overwrite of a column/file gets: a guard (`WHERE` + `LIMIT`), a dry-run count first, a backup or snapshot when anything of value exists, and an undo path (soft delete, staging table, or copy) for user-facing data.
|
|
18
|
+
3. **Migrations are code that runs on data you cannot recreate.** Checked in from day one, reviewed as SQL before applying (ORM-generated SQL included — generators will happily emit `DROP COLUMN` for a rename), never edited once applied, forward-only in production. `db push`-style sync is for throwaway dev databases only.
|
|
19
|
+
4. **One logical change, one transaction.** Multi-step writes either all land or none do. Anything a retry can hit twice (webhooks, queue jobs, imports, payment callbacks) is idempotent — a dedup key or upsert, not hope.
|
|
20
|
+
5. **Backups you have not restored are fiction.** Automated, off-platform (or at least off-instance), on anything with real user data — and the restore is exercised, timed, and recorded. RPO (how much loss is acceptable) and RTO (how long recovery takes) are stated numbers, not vibes.
|
|
21
|
+
6. **Fail loudly, not corruptly.** Partial imports, half-applied backfills, and crashed jobs leave the system in a state the next run can detect and resume — keyset-resumable batches, recorded checkpoints, no silent skips.
|
|
22
|
+
7. **Respect the writer.** SQLite has one writer; Postgres connections are processes; serverless poolers multiplex transactions and break session state. Designing against the store's real concurrency model is durability work, not just performance work.
|
|
23
|
+
8. **Numbers or silence.** A backup claim without a timed restore run is unverified. Label every claim `RUNTIME` (observed), `CODE` (read in source), `DEDUCED` (inferred), `SNAPSHOT` (dated source). Never claim data is "safe" — say what loss is survivable and what is not.
|
|
24
|
+
9. **Proportionality.** A prototype with test rows needs migrations and little else. The first real user row raises the floor: backups, then tested restore, then PITR-class recovery as the product matters.
|
|
25
|
+
|
|
26
|
+
## Two modes
|
|
27
|
+
|
|
28
|
+
**Inline gate** — while writing anything that touches stored data: the first table, a schema change, a backfill or import script, a delete/edit endpoint, a webhook that writes, a backup cron. Apply the binding defaults below, say one line about the guard you built, move on. Do not stop the build to lecture, and do not ship the unguarded version intending to "add safety later".
|
|
29
|
+
|
|
30
|
+
**Full pass** — triggered by "is my data safe", "will I lose my data if X", "back up my app", a migration about to run on production, or after any data scare. Run the workflow below. Migration and schema detail lives in `references/migrations-and-schema.md`; backups, recovery, and runtime data-safety detail lives in `references/backups-and-runtime.md`.
|
|
31
|
+
|
|
32
|
+
## Binding defaults (build mode)
|
|
33
|
+
|
|
34
|
+
Apply on every data-touching change, every store:
|
|
35
|
+
|
|
36
|
+
- **Migration tooling from the first table** — checked-in versioned migrations, generated with `--create-only`-style review when the ORM supports it, reviewed as SQL, applied via the tool's deploy path. Never hand-edit an applied migration; write a new one that corrects it.
|
|
37
|
+
- **Destructive ops carry their guard** — `WHERE` + `LIMIT` on mass changes, count-first dry run (`SELECT` the affected rows before `DELETE`/`UPDATE`), and for user-visible data prefer soft delete (`deleted_at`) with partial unique indexes over hard delete until retention policy says otherwise.
|
|
38
|
+
- **Constraints in the store** — `NOT NULL` on required fields, `UNIQUE` where identity lives (email, external IDs), foreign keys with explicit `ON DELETE` behavior chosen (not defaulted), and `CHECK` where a value has a domain. Orphaned rows and duplicate emails are app bugs the DB should have refused.
|
|
39
|
+
- **Transactions around multi-write invariants** — wrap create-order-plus-items, transfer-out-plus-transfer-in, and every read-modify-write that must not interleave. Where the store lacks multi-document transactions, the default is a single-document design or an outbox pattern, never "should be fine".
|
|
40
|
+
- **Idempotency keys on retried writes** — webhook event IDs, job dedup keys, `INSERT ... ON CONFLICT` upserts. Rule of thumb: if it can run twice, assume it will.
|
|
41
|
+
- **Batched, resumable bulk work** — keyset pagination (`WHERE id > last`), fixed batch size, sleep between batches, checkpoint recorded so a crash resumes rather than restarts or double-applies. Never one unbounded `UPDATE` over a production table.
|
|
42
|
+
- **Backups the moment real data exists** — automated (managed-provider backups, `pg_dump` cron, Litestream for SQLite, scheduled snapshots for document stores), retention of days not one copy, at least one copy off the same machine/account. State RPO/RTO in a comment where the backup is configured.
|
|
43
|
+
- **Connection and session hygiene** — close/release connections in `finally`; on serverless, assume transaction-mode pooling (no session state, no prepared statements unless the pooler supports them, no `LISTEN/NOTIFY`, no session advisory locks); one pool per function instance, not per request.
|
|
44
|
+
- **SQLite as SQLite** — WAL mode on, `busy_timeout` set, one writer (route writes through a single instance or a queue), database on local disk not network storage, Litestream-or-scheduled-backup for continuous protection. Do not pretend it is a client-server DB.
|
|
45
|
+
|
|
46
|
+
## Full-pass workflow
|
|
47
|
+
|
|
48
|
+
### 1. Profile the data from the code
|
|
49
|
+
|
|
50
|
+
Before asking anything: store type(s) and version, where data files live, ORM/migration tooling present or absent, what writes exist (endpoints, jobs, webhooks, imports), what deletes exist, whether backups are configured anywhere (deploy config, cron, provider settings), and — decisive — whether real user data exists. A repo with seed scripts only is a different engagement than one with a production URL.
|
|
51
|
+
|
|
52
|
+
### 2. Establish what loss would mean
|
|
53
|
+
|
|
54
|
+
From the code, answer: what is recreated (cache, derived data), what is user-entered and unrecoverable (posts, uploads, messages, payments), and what links out (files on disk referenced by rows, rows referencing deleted files). The unrecoverable set defines backup urgency; the links define cleanup discipline.
|
|
55
|
+
|
|
56
|
+
### 3. Sweep the six areas
|
|
57
|
+
|
|
58
|
+
In order of how often each actually loses data. Detection specifics and commands: the two reference files.
|
|
59
|
+
|
|
60
|
+
| # | Area | What you are hunting |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| 1 | **Backups & recovery** | No backups at all; backups only on the same machine/account; no retention; never-restored backups (the norm); no stated RPO/RTO; single copy of file uploads; managed backups assumed but not enabled |
|
|
63
|
+
| 2 | **Destructive paths** | `DELETE`/`UPDATE` without `WHERE` or `LIMIT`; cascade deletes that sweep further than intended (user → everything they own, intended or not); truncate/drop in scripts; no undo for user-facing deletes; `db push` or sync-style schema changes anywhere near production config |
|
|
64
|
+
| 3 | **Migrations health** | No migration tooling (schema by hand/script); applied migrations edited; pending destructive migration; generated SQL never reviewed; migrations untested against prod-shaped data; drift between schema files and the live DB |
|
|
65
|
+
| 4 | **Transactions & idempotency** | Multi-step writes without a transaction; webhook/job handlers that double-apply on retry; check-then-act races (read, decide, write without a constraint); imports that restart from zero |
|
|
66
|
+
| 5 | **Schema integrity** | Foreign keys absent or off (MySQL engines, SQLite `PRAGMA foreign_keys`); duplicate-prone columns without unique constraints; orphaned rows; `NOT NULL`-in-spirit columns that are nullable in fact; money/IDs stored in lossy types (float money, int IDs near overflow) |
|
|
67
|
+
| 6 | **Runtime data safety** | Transaction-pooled connections using session features; SQLite without WAL/busy_timeout or with concurrent writers across instances; files written non-atomically (no temp-then-rename); jobs that mutate state with no record of having run; queues with no dead-letter path |
|
|
68
|
+
|
|
69
|
+
### 4. Rank by survivability
|
|
70
|
+
|
|
71
|
+
| Severity | Meaning |
|
|
72
|
+
|---|---|
|
|
73
|
+
| **Critical** | Loss is certain or one common failure away: real user data with no backups; destructive path unguarded; pending migration that drops data; double-charge/double-apply on retry |
|
|
74
|
+
| **High** | Loss on a plausible bad day: backups exist but never restored; single copy on one machine/account; cascade deletes broader than intended; multi-write flows without transactions |
|
|
75
|
+
| **Medium** | Fragility that bites at scale or during recovery: missing constraints, schema drift, non-idempotent jobs, non-atomic file writes |
|
|
76
|
+
| **Low** | Hygiene: naming, unused staging tables, comments. Do these when adjacent to a real fix. |
|
|
77
|
+
|
|
78
|
+
Fix Critical and High first; three to five fixes, each verified. A backup you set up is finished only when a restore from it has run and been timed.
|
|
79
|
+
|
|
80
|
+
### 5. Verify
|
|
81
|
+
|
|
82
|
+
- **Restore drill for any backup fix**: snapshot state, note the time, make a recognizable change, restore to the noted time into a separate location, verify the change is absent, record the wall-clock duration — that number is the real RTO. `RUNTIME` label or it did not happen.
|
|
83
|
+
- **Guard drill for any destructive fix**: run the guarded path against a copy with a row that must survive and a row that must not; assert both outcomes.
|
|
84
|
+
- **Migration drill**: apply the pending migrations to a copy of production-shaped data (a fresh dump, a seeded volume) before it goes near the real thing.
|
|
85
|
+
- Label what you could not run — no environment, no data copy, managed console you cannot touch — as unverified, and say the exact command the user should run.
|
|
86
|
+
|
|
87
|
+
### 6. Leave a guard behind
|
|
88
|
+
|
|
89
|
+
A tested restore cron'd into a weekly job; a CI step that applies migrations to a throwaway DB before merge; a test that a retried webhook applies once; a constraint added to the store; `--create-only` review in the project's migration docs. One mechanical check beats a README paragraph.
|
|
90
|
+
|
|
91
|
+
### 7. Report
|
|
92
|
+
|
|
93
|
+
- Lead with the survivability statement in plain words: "if this server dies right now, you lose everything after [backup point]" — the RPO the user actually has, not the one they think they have.
|
|
94
|
+
- Then findings ranked, each with file/line and the fix.
|
|
95
|
+
- Then what was **not checked** — stores skipped, consoles inaccessible, uploads unexamined.
|
|
96
|
+
- Then what you fixed (with verification labels) vs. what needs the user (provider settings, paid tiers, their call on retention).
|
|
97
|
+
- Label every claim `RUNTIME` / `CODE` / `DEDUCED` / `SNAPSHOT`.
|
|
98
|
+
|
|
99
|
+
## Honesty rules
|
|
100
|
+
|
|
101
|
+
- Never state or imply data is "safe" or "backed up" without an observed, timed restore. "Backups are configured" is a `CODE` claim; "recoverable" requires a `RUNTIME` one.
|
|
102
|
+
- Never present a retention number, provider tier, or version behavior as current without verifying — provider backup defaults change; mark the snapshot date.
|
|
103
|
+
- Never run a destructive command, however obviously safe, against a database with real data without an explicit backup or the user's go-ahead.
|
|
104
|
+
- "I could not verify this" is a legitimate output. A fabricated restore test is the worst lie this skill could tell.
|
|
105
|
+
|
|
106
|
+
## Reference map
|
|
107
|
+
|
|
108
|
+
Resolve every path from the installed skill root. Load only what the profile triggered.
|
|
109
|
+
|
|
110
|
+
- `references/migrations-and-schema.md` — the migration discipline: expand-contract with concrete lock behavior, batched resumable backfills, index and FK lock-safety, ORM-specific traps (Prisma, Drizzle, and friends), forward-only production, CI and deploy-time application, and schema integrity checks. Read for any migration or schema finding.
|
|
111
|
+
- `references/backups-and-runtime.md` — backup tiers and the restore drill, RPO/RTO, 2026 managed-provider baselines (Supabase, Neon, RDS, Crunchy), self-hosted tooling (pgBackRest, WAL-G, Litestream, restic), file-upload protection, idempotency and outbox patterns, pooling and serverless session-state pitfalls, SQLite runtime rules, and atomic file writes. Read for any backup, recovery, or runtime finding.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Durable — backups, recovery & runtime data safety
|
|
2
|
+
|
|
3
|
+
Load for any backup, recovery, or runtime finding. `SNAPSHOT` = sourced 17 August 2026 — provider tiers and defaults change often; verify before asserting.
|
|
4
|
+
|
|
5
|
+
## Part 1 — Backups & recovery
|
|
6
|
+
|
|
7
|
+
### RPO/RTO first
|
|
8
|
+
|
|
9
|
+
- **RPO** (Recovery Point Objective): how much data loss is acceptable — "5 minutes" vs "a day".
|
|
10
|
+
- **RTO** (Recovery Time Objective): how long until you are back up.
|
|
11
|
+
|
|
12
|
+
Pick both consciously; they dictate the tier. An app where users type for hours wants an RPO near zero; a read-mostly catalog may accept a day. Stating them where the backup is configured turns "we have backups" into an actual contract.
|
|
13
|
+
|
|
14
|
+
### The tiers, best to weakest
|
|
15
|
+
|
|
16
|
+
1. **PITR (point-in-time recovery)** — base backup + continuous write-ahead-log archive; restore to any second in the retention window. RPO of seconds-to-minutes. Gold standard for transactional data.
|
|
17
|
+
2. **Scheduled logical dumps** (`pg_dump`, `mongodump`, Firestore export) — portable, cheap, easy to verify by inspection; but restore time scales with size and everything after the dump starts is lost. Fine as the archive layer or the only layer for small apps.
|
|
18
|
+
3. **Storage/block snapshots** — fast, near-zero impact; restoring a running DB from a raw snapshot leaves crash recovery to do the rest. Good for staging clones; for disaster recovery prefer PITR.
|
|
19
|
+
4. **Nothing / a copy on the same machine** — the default state of most small projects, and the finding most often reported after it stops mattering.
|
|
20
|
+
|
|
21
|
+
**3-2-1 floor**: at least 3 copies, 2 different media/systems, 1 off-site (different provider or account is fine). A dump cron writing to the same VPS is one disk failure from zero.
|
|
22
|
+
|
|
23
|
+
### Managed-provider baselines (`SNAPSHOT` 17 Aug 2026 — verify tiers/retention before quoting)
|
|
24
|
+
|
|
25
|
+
| Provider | What you get by default/on paid tiers |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Supabase | Pro: 7-day PITR included; daily logical backups; restore lands a new project |
|
|
28
|
+
| Neon | Continuous WAL archive; PITR up to 30 days on higher tiers; branching doubles as time-travel |
|
|
29
|
+
| AWS RDS | Automated backups 1–35 days (PITR); manual snapshots on demand |
|
|
30
|
+
| Crunchy Bridge | 14-day PITR by default; longer via S3 archive |
|
|
31
|
+
| MongoDB Atlas | Continuous backup / cloud snapshots by tier |
|
|
32
|
+
|
|
33
|
+
The recurring failure: the free tier's weekly backup or none at all, assumed to be PITR because the marketing page said "backups". Check the project's actual settings, not the provider's homepage.
|
|
34
|
+
|
|
35
|
+
**Self-hosted Postgres**: pgBackRest, Barman, or WAL-G → S3-compatible storage. **Self-hosted/embedded SQLite**: Litestream (continuous WAL replication to object storage, near-zero RPO) or restic/borg on a schedule as the weaker floor. **Firestore/DynamoDB-style**: scheduled exports to storage — PITR is a paid or absent feature; check the project's state.
|
|
36
|
+
|
|
37
|
+
### The restore drill (the only proof)
|
|
38
|
+
|
|
39
|
+
1. Note the current time / snapshot point of a known state.
|
|
40
|
+
2. Make a recognizable change (insert a canary row).
|
|
41
|
+
3. Restore to the noted point into a *separate* location — never over the live DB.
|
|
42
|
+
4. Verify the canary is absent. Time the whole operation — that measured duration is the real RTO; write it down.
|
|
43
|
+
5. Repeat on a schedule (quarterly is the common bar); the drill doc itself is the runbook you'll follow at 3am.
|
|
44
|
+
|
|
45
|
+
**File uploads need their own answer** — DB backups don't cover a disk of user uploads unless the backup includes the volume or the uploads live in object storage with versioning (S3 versioning or equivalent preserves deleted/overwritten objects — turn it on and state the retention). DB row + orphaned-file mismatch is a finding: cleanup discipline (delete file then row, in that order, with the row's file path recorded for resweep) or accept orphans.
|
|
46
|
+
|
|
47
|
+
### What a backup must exclude/include
|
|
48
|
+
|
|
49
|
+
Include: the data, schema history (migrations), and anything unrecreatable (uploads, generated-but-expensive artifacts). Exclude/rotate: secrets in plaintext dumps (a dump with PII inherits compliance-guard's storage rules — encrypt at rest, restrict access), logs, caches. Test that the restore includes what you think: a backup that skips a table because of a wrong flag is the most humiliating restore failure.
|
|
50
|
+
|
|
51
|
+
## Part 2 — Runtime data safety
|
|
52
|
+
|
|
53
|
+
### Idempotency & exactly-once writes
|
|
54
|
+
|
|
55
|
+
Anything retried — webhooks, queue jobs, mobile clients on flaky networks, imports — **will** run twice. Patterns, in order of preference:
|
|
56
|
+
|
|
57
|
+
- **Store-side dedup**: unique constraint on the natural key (webhook event ID, job ID + attempt) and `INSERT ... ON CONFLICT DO NOTHING` returning whether it inserted. The store is the arbiter; no race can beat it.
|
|
58
|
+
- **Upsert by natural key**: `ON CONFLICT ... DO UPDATE` with a deterministic outcome, so replay converges instead of duplicating.
|
|
59
|
+
- **Compare-and-set / optimistic concurrency**: `UPDATE ... WHERE version = :expected`, check affected count — the guard for read-modify-write races (balance updates, seat claims, counter increments).
|
|
60
|
+
- **Outbox pattern**: state changes and the events they trigger written in one transaction to an outbox table, published by a separate relay — eliminates "DB updated but email/queue lost" (and its evil twin, "email sent but DB rolled back"). The default answer where a store lacks cross-service transactions.
|
|
61
|
+
|
|
62
|
+
Check-then-act without a constraint (`if not exists: insert`) is a bug that just hasn't raced yet.
|
|
63
|
+
|
|
64
|
+
### Connection & session pitfalls (correctness, not speed)
|
|
65
|
+
|
|
66
|
+
- **Transaction-mode poolers** (PgBouncer/Supavisor, Neon pooler, RDS Proxy defaults): each transaction may run on a different connection — session state breaks. Casualties: session-level `SET`/`prepared statements` (named ones), advisory locks, `LISTEN/NOTIFY`, temp tables, `COPY`. Patterns: keep per-transaction state in SQL (`SET LOCAL`), use `pg_advisory_xact_lock` (transaction-scoped), or route state-needing work to a direct/session connection.
|
|
67
|
+
- **Serverless functions**: one pool per *instance* (module scope), never per request; assume the process freezes between invocations — no in-memory "it'll flush later".
|
|
68
|
+
- **Postgres connections are processes** — exhausting them fails every new client; the fix is a pooler, not a bigger `max_connections`. (Sizing the pool for throughput is lean's lane.)
|
|
69
|
+
- **Always release/close in `finally`** — a leaked connection per request is a slow outage and a durability finding.
|
|
70
|
+
|
|
71
|
+
### SQLite runtime rules
|
|
72
|
+
|
|
73
|
+
- **WAL mode on** (`PRAGMA journal_mode=WAL`) — readers don't block the writer; the default rollback journal serializes everything.
|
|
74
|
+
- **`busy_timeout` set** (e.g. 5000ms) — without it, concurrent access returns `SQLITE_BUSY` instantly instead of waiting.
|
|
75
|
+
- **`PRAGMA foreign_keys = ON` on every connection** — it is per-connection and off by default; constraints silently unenforced is a schema-integrity finding wearing runtime clothes.
|
|
76
|
+
- **One writer** — route writes through a single instance or a write queue; multiple app instances writing one SQLite file on shared/network storage corrupts. Local disk (NVMe), not NFS.
|
|
77
|
+
- **Backup without Litestream**: `VACUUM INTO 'backup.db'` or the `sqlite3 .backup` command — never copy the file mid-write; the WAL file and the checkpoint state are part of the database.
|
|
78
|
+
|
|
79
|
+
### Atomic file writes and cleanup
|
|
80
|
+
|
|
81
|
+
- **Temp-then-rename** for any file a reader may open: write to `path.tmp`, `fsync`, then `rename` over the target. Atomic on POSIX; a crash mid-write never leaves a truncated JSON the app will happily parse.
|
|
82
|
+
- **Delete in dependency order and resweep**: child rows then parent; file after the row referencing it is gone (or record orphans for a sweep job). Reversible orderings first: soft-delete the row, mark the file, sweep files later — undoability beats tidiness.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
**Provenance:** snapshot 17 August 2026. Sources: Postgres WAL/PITR documentation and pgBackRest/Barman/WAL-G docs, Litestream documentation (SQLite WAL replication), provider documentation for Supabase/Neon/RDS/Crunchy/MongoDB Atlas backup tiers (tier specifics are `SNAPSHOT` — they change often), PgBouncer documentation (transaction-mode feature matrix), SQLite documentation (WAL, busy_timeout, foreign_keys pragma, VACUUM INTO), current disaster-recovery practice guides (3-2-1, RPO/RTO, restore drills). Provider tiers and defaults decay fastest — re-verify before asserting.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Durable — migrations & schema
|
|
2
|
+
|
|
3
|
+
Load for any migration or schema finding. Postgres examples dominate because it is the default; MySQL and SQLite divergences are called out. `SNAPSHOT` = sourced 17 August 2026 — version behaviors decay, verify before asserting.
|
|
4
|
+
|
|
5
|
+
## The one rule that prevents most downtime
|
|
6
|
+
|
|
7
|
+
**Never deploy a schema change and the code that depends on it in the same step.** Old code must keep working against the new schema, and new code must keep working against the old schema, for at least one deploy cycle. That is what expand-contract buys.
|
|
8
|
+
|
|
9
|
+
## Expand-contract (parallel change)
|
|
10
|
+
|
|
11
|
+
Every breaking change is two or three separately-deployed steps, each leaving the system fully functional:
|
|
12
|
+
|
|
13
|
+
1. **Expand** — add the new column/table/index (nullable, no constraints yet). Old code ignores it; nothing breaks.
|
|
14
|
+
2. **Backfill + dual-write** — copy old data to new in batches; code writes both; code reads new with fallback to old. Deploy, watch, wait.
|
|
15
|
+
3. **Contract** — after the old path is provably dead (feature flag flipped, traffic at zero), remove the old column and the dual-write.
|
|
16
|
+
|
|
17
|
+
Rollback at any point is "flip back to the old path", not "restore the database".
|
|
18
|
+
|
|
19
|
+
**Rename a column** — never `RENAME COLUMN` on a live system (breaks all in-flight code): add `email`, backfill from `email_addr`, dual-write, switch reads, drop `email_addr` in a later deploy.
|
|
20
|
+
|
|
21
|
+
**Change a type or split a column** — add the new column, backfill with transformation in batches, cut writes over, drop old. Same shape, always.
|
|
22
|
+
|
|
23
|
+
## Lock-safety table (Postgres)
|
|
24
|
+
|
|
25
|
+
What common DDL actually does to a live table (`SNAPSHOT` — verify per version):
|
|
26
|
+
|
|
27
|
+
| Operation | Behavior | Safe pattern |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `ADD COLUMN` (no default) | Fast, brief lock | Fine as-is |
|
|
30
|
+
| `ADD COLUMN ... NOT NULL DEFAULT x` | Fast since Postgres 11 (default not backfilled); table rewrite before 11 | Fine on ≥11; otherwise add nullable → backfill → `SET NOT NULL` |
|
|
31
|
+
| `SET NOT NULL` on existing column | Full-table scan under lock | Backfill first, then set; or add a `CHECK` constraint `NOT VALID` then `VALIDATE`, then switch |
|
|
32
|
+
| `CREATE INDEX` | Blocks writes for the whole build | `CREATE INDEX CONCURRENTLY` (drop with `DROP INDEX CONCURRENTLY`); slower, non-transactional — if it fails, drop the invalid index and retry |
|
|
33
|
+
| `ADD FOREIGN KEY` | Locks while validating all rows | Two-step: `ADD CONSTRAINT ... NOT VALID` then `VALIDATE CONSTRAINT` (weaker lock) |
|
|
34
|
+
| One giant `UPDATE`/`DELETE` | Locks rows, bloats the table, stalls replication | Batch: keyset-select N rows → update → sleep → repeat, resumable from last key |
|
|
35
|
+
| `DROP COLUMN` | Fast (metadata) — but data is gone | Only in the contract phase, after dual-write is verified dead |
|
|
36
|
+
|
|
37
|
+
MySQL has no `CONCURRENTLY`: use `ALGORITHM=INSTANT/INPLACE` where the version supports it, `gh-ost` or `pt-online-schema-change` for big tables (`SNAPSHOT` — both maintained; verify current). Postgres big-table rebuilds (PK change, deep bloat, partitioning): `pg_repack`, which rebuilds online with minimal locking and needs ~2x disk temporarily.
|
|
38
|
+
|
|
39
|
+
## Resumable backfill skeleton
|
|
40
|
+
|
|
41
|
+
```sql
|
|
42
|
+
-- keyset, not OFFSET: stable order, restartable from last processed id
|
|
43
|
+
UPDATE users
|
|
44
|
+
SET status = 'active'
|
|
45
|
+
WHERE id IN (
|
|
46
|
+
SELECT id FROM users WHERE id > :last_id AND status IS NULL
|
|
47
|
+
ORDER BY id LIMIT 5000
|
|
48
|
+
)
|
|
49
|
+
RETURNING id; -- record max(id) as the checkpoint; sleep between batches
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
From application code the same shape applies: select batch by `id > last`, write, record checkpoint durably (a checkpoint table or job state), sleep. A crashed backfill resumes at the checkpoint instead of restarting or double-writing. On stores without `RETURNING`, select the batch first, update by primary key, checkpoint the max selected id.
|
|
53
|
+
|
|
54
|
+
## Migration tooling discipline
|
|
55
|
+
|
|
56
|
+
- **Versioned, checked-in migrations from the first table** — Alembic (Python), Flyway/Liquibase (JVM), golang-migrate (Go), sqlx/Diesel (Rust), Drizzle Kit / Prisma Migrate (TS). Hand-run SQL files and "schema.sql we run sometimes" are how drift starts.
|
|
57
|
+
- **Review generated SQL before it touches anything real.** ORM migration generators emit what the schema diff implies: renaming a column in the schema file becomes `DROP COLUMN` + `ADD COLUMN` — the data is dropped. Prisma flow: `migrate dev --create-only`, read the SQL, fix it to a safe expand-contract, then apply. Drizzle: generate, then read the SQL before `migrate`. This review is the single highest-value habit in this file.
|
|
58
|
+
- **`db push`/sync-style commands are for throwaway dev databases only.** They bypass migration history; on a database with data they can apply destructive diffs without review. If a deploy script or CI contains `db push` against anything shared or persistent, that is a finding.
|
|
59
|
+
- **Never edit an applied migration.** The hash changes, history diverges, teammates' databases desync. Corrections are new migrations.
|
|
60
|
+
- **Forward-only in production.** Down migrations cannot faithfully reverse a migration that touched data (you cannot un-drop a column). "Rollback" is a new forward migration that reverses the change, written and tested like any other. Down migrations are a dev convenience at most.
|
|
61
|
+
- **Apply migrations as a distinct step before the new code rolls out** (deploy script step or pre-deploy Job), never lazily on first request, never concurrently from every replica. One applier, ordered, recorded.
|
|
62
|
+
|
|
63
|
+
## CI and testing
|
|
64
|
+
|
|
65
|
+
- A CI job that applies all migrations to a throwaway database (a fresh dump or seed of production shape) on every PR — catches broken SQL and lock surprises before merge, and keeps prod-shaped test data honest.
|
|
66
|
+
- Migration + dependent code in one PR is fine; shipping them as one *deploy step* is not — expand and contract are separate deploys even when they merge as one review.
|
|
67
|
+
|
|
68
|
+
## Schema integrity sweep
|
|
69
|
+
|
|
70
|
+
- **Foreign keys enforced?** MySQL: check the engine (InnoDB enforces, MyISAM does not). SQLite: `PRAGMA foreign_keys = ON` per connection — it is OFF by default and every connection must set it. Postgres: on by default; hunt instead for `ON DELETE` behavior nobody chose — cascade on a `users` delete that sweeps orders, messages, and uploads is a mass-delete path wearing a constraint's clothing.
|
|
71
|
+
- **Unique constraints where identity lives** — email, username, external IDs (`stripe_customer_id`), webhook event IDs. Without the constraint, every race produces a duplicate; with it, the race becomes a retryable error. Partial unique indexes for soft delete: `CREATE UNIQUE INDEX ... ON users(email) WHERE deleted_at IS NULL` — the live rows stay unique, the deleted ones don't collide.
|
|
72
|
+
- **Nullable-in-fact columns** — every column the code treats as required should be `NOT NULL`, or the store will accept what the code never imagined.
|
|
73
|
+
- **Lossy types** — money in floating point (use integer cents or `NUMERIC`), IDs in 32-bit ints near overflow (YouTube hit this), timestamps without timezone when the product is multi-timezone, enums-as-free-text where a `CHECK` or lookup table belongs.
|
|
74
|
+
- **Orphan check** — rows referencing deleted parents (FKs added late don't clean history): count them before adding the constraint, and expect `VALIDATE` to fail if history is dirty. Decide: clean, archive, or keep the constraint `NOT VALID` deliberately and document why.
|
|
75
|
+
- **Drift** — schema file vs live DB: most ORMs can diff (`prisma migrate diff`, `drizzle-kit check`). Drift on production means migrations were bypassed at some point — a process finding, not just a schema one.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
**Provenance:** snapshot 17 August 2026. Sources: Postgres documentation (DDL locking behavior, `CONCURRENTLY`, `NOT VALID`/`VALIDATE`, ADD COLUMN default fast-path), current zero-downtime migration practice guides (expand-contract/parallel-change, batched keyset backfill, forward-only production, pre-deploy application), Prisma/Drizzle documentation (create-only review workflow, `db push` scope), MySQL online-schema-change tooling (gh-ost, pt-online-schema-change) public docs. Version-specific lock behavior decays fastest — re-verify against the running version before asserting.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lean
|
|
3
|
+
description: Use when speed or resource efficiency matters — slow loading or startup, janky interaction, high CPU, memory leaks or RAM that grows over time, zombie/orphan processes, bundle bloat, dead code and dead styles, Core Web Vitals; while building anything that should stay fast and light, running a performance pass over an existing project, or pre-ship "will this run smoothly" checks. Any stack — web, backend/API/CLI, desktop (Electron, Tauri), mobile, native, game, ML pipeline. Do NOT use for copy/docs-only changes, design-direction or aesthetic work (that is evidence-led-ui; this skill's styling scope is payload and consistency), or when the user explicitly deprioritizes performance.
|
|
4
|
+
license: Performance engineering guidance, not a benchmark certification. Sources and snapshot date are recorded at the foot of each reference file.
|
|
5
|
+
compatibility: Snapshot dated 17 August 2026. Thresholds, tool names, and defaults decay — re-verify with web access before asserting them as current. Claims sourced to that date carry a SNAPSHOT marker.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Lean
|
|
9
|
+
|
|
10
|
+
Make software fast, light, and smooth — loads quick, responds instantly, holds memory flat, leaves nothing running behind it. Built for the reality that users rarely ask for performance: they ask for a feature, then quietly leave when it eats RAM or takes five seconds to open.
|
|
11
|
+
|
|
12
|
+
**This skill is on from the first line of code.** The default mode is the inline gate below — build the lean version while writing the feature, in the main thread. The full pass is for existing projects and pre-ship checks.
|
|
13
|
+
|
|
14
|
+
## Governing rules
|
|
15
|
+
|
|
16
|
+
1. **Measure, then cut.** In a pass, never optimize from vibes: baseline, find the bottleneck, fix it, re-measure. Guessing produces premature optimization — complexity without user-visible gain. In build mode the binding defaults below are pre-paid by platform evidence: apply them without benchmarking.
|
|
17
|
+
2. **Fix the shared cause once.** The N+1 belongs in the query layer, not a memo at each call site. Check every caller of the slow path before patching where it hurt.
|
|
18
|
+
3. **Optimize user time, not machine time.** What users wait on: startup, first paint, navigation, hot interactions, the nightly job. Micro-tuning code nobody waits for is last, always.
|
|
19
|
+
4. **Memory should be flat.** After N cycles of the core loop, committed memory should look like after 1. Sustained growth is a leak until proven otherwise; a sawtooth that returns to baseline is GC, not a leak.
|
|
20
|
+
5. **Nothing outlives its job.** Timers, listeners, observers, subscriptions, watchers, child processes, temp files, locks — everything with a lifetime needs an owner that ends it, on the success path *and* every failure path.
|
|
21
|
+
6. **Bounded by default.** If it can grow — cache, queue, buffer, retry, log, list render — it gets a cap and an eviction policy at creation, not after the incident.
|
|
22
|
+
7. **Small is fast.** Dead code, unused dependencies, and duplicate styles are parsed, shipped, and paid for. Removing is the cheapest optimization there is.
|
|
23
|
+
8. **Numbers or silence.** Verify with before/after on the same machine and data, cold and warm. "Feels faster" is not a result, and never claim "optimized", "leak-free", or "fast" — say what moved, from X to Y, and what you could not measure.
|
|
24
|
+
9. **No perf theater.** Complexity must pay for itself in measured user time; otherwise revert. Caching that introduces staleness bugs for an unmeasured gain is a regression wearing a costume.
|
|
25
|
+
10. **Label evidence** on every claim: `RUNTIME` (you measured it), `CODE` (you read it), `DEDUCED` (inferred), `SNAPSHOT` (dated source claim). Never present what you read as what you ran.
|
|
26
|
+
|
|
27
|
+
## Two modes
|
|
28
|
+
|
|
29
|
+
**Inline gate** — while writing any feature, apply the binding defaults below. One line in the reply about what you did and why it matters, then move on. Do not stop the build to lecture, and do not ship the heavy version intending to "optimize later" — later never comes.
|
|
30
|
+
|
|
31
|
+
**Full pass** — triggered by "make it faster", "why is it slow / eating RAM / lagging", "will this run smoothly", a suspected regression, or a pre-ship check. Run the workflow below. Per-stack sweeps and measurement commands live in `references/playbooks.md`; the memory-leak catalog and process/zombie lifecycle detail live in `references/memory-and-processes.md`.
|
|
32
|
+
|
|
33
|
+
## Binding defaults (build mode)
|
|
34
|
+
|
|
35
|
+
Apply on every feature, every stack. These are the habits that prevent the pass from ever being needed:
|
|
36
|
+
|
|
37
|
+
- **Teardown ships with the feature.** Whatever you start — timer, listener, observer, subscription, child process, watcher — is torn down in the same module that started it, on success and error paths. Prefer one cleanup handle per owner (an `AbortController` for all of a component's fetches and listeners; a destructor/dispose method; a `finally` block) over scattered manual removes.
|
|
38
|
+
- **Cap every accumulation.** LRU/TTL cache, bounded queue, paginated query, virtualized list, capped retries with backoff, rotating logs. Unbounded is a bug with a delay.
|
|
39
|
+
- **Never block the interactive thread.** Chunk, defer, or offload work that can exceed a frame (web main thread long task threshold: 50ms) — web workers, background threads, task queues, utility processes. I/O stays async on the hot path; no sync fs/crypto/CPU spikes inside request handlers or UI code.
|
|
40
|
+
- **Lazy by default, eager only for the first screen.** Below-the-fold media, rare routes, heavy editors, optional services: load on demand (dynamic `import()`, deferred `require`, on-demand plugin init). Preload/preconnect only what the critical path demonstrably needs.
|
|
41
|
+
- **Right-size media.** AVIF/WebP with JPEG fallback, explicit `width`/`height` (also kills layout shift), `srcset`/`sizes` for density, decode thumbnails instead of full images.
|
|
42
|
+
- **Stream, don't hoard.** Stream files and large responses, paginate/cursor DB queries, chunk large jobs. Loading a whole dataset into memory to process it item by item is the classic hog.
|
|
43
|
+
- **Timeout everything external.** Network calls, subprocesses, locks, queues — no unbounded waits, and teardown on timeout.
|
|
44
|
+
- **Price a dependency before adopting it** in anything user-facing: its load cost is your load cost (`node --cpu-prof --heap-prof -e "require('mod')"` for Node-side; bundle impact for client-side). The most-downloaded module is not the lightest.
|
|
45
|
+
- **Batch I/O and reads-then-writes.** One query for N rows, not N queries; group DOM reads before writes; coalesce events (debounce/throttle) when handlers are expensive.
|
|
46
|
+
|
|
47
|
+
## Full-pass workflow
|
|
48
|
+
|
|
49
|
+
### 1. Profile the target from the code
|
|
50
|
+
|
|
51
|
+
Before asking the user anything: shape (web app, API, CLI, desktop, mobile, library, game, ML pipeline — read manifests, lockfiles, build and CI configs), the surfaces users wait on (startup, first screen, navigation, hot interactions, batch jobs), scale (data sizes, traffic, session length), and platform constraints (low-end devices matter more than the dev machine).
|
|
52
|
+
|
|
53
|
+
### 2. Baseline, or say you cannot
|
|
54
|
+
|
|
55
|
+
Runtime numbers when the project runs: load time, startup time, p50/p99 latency, bundle sizes, RSS/heap at rest and after repeated cycles. Exact commands per stack are in `references/playbooks.md`. If you cannot run it (no environment, no data, no time), do a `CODE`-labeled static pass and say plainly in the report that nothing was measured — do not fabricate a baseline.
|
|
56
|
+
|
|
57
|
+
### 3. Sweep the six areas
|
|
58
|
+
|
|
59
|
+
Work this list in order — it reflects where user-perceived damage concentrates, not what is most interesting to engineer. Detection specifics per stack: `references/playbooks.md`; areas 3–4: `references/memory-and-processes.md`.
|
|
60
|
+
|
|
61
|
+
| # | Area | What you are hunting |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| 1 | **Loading & startup** | Slow first paint/open, render-blocking resources, giant bundles, eager imports of rarely-used code, waterfall requests, unoptimized media and fonts, cold-start work that could be deferred |
|
|
64
|
+
| 2 | **Runtime responsiveness** | Long tasks blocking input, layout thrash, expensive re-renders, N+1 queries, sync work on hot paths, missing pagination, unvirtualized long lists, GC pressure from allocation churn |
|
|
65
|
+
| 3 | **Memory** | Growth over time (leaks): forgotten timers/listeners/observers, detached DOM held alive, unbounded caches and maps, closures capturing large scope, cycles in non-GC runtimes, undecoded-or-full-size media, whole-file loads where streaming would do |
|
|
66
|
+
| 4 | **Processes & lifecycle** | Zombie children (spawned, never reaped), orphans surviving parent exit (killed the node, not the tree), missing signal handling and graceful shutdown, leaked ports/fds/locks/temp files, no startup sweep for crash leftovers |
|
|
67
|
+
| 5 | **Payload & dead weight** | Unused dependencies, dead code and dead exports, dead/duplicate CSS, two libraries doing one job (two icon sets, two date libs, two CSS systems), ship-weight of debug/symbol payloads, tree-shaking blockers |
|
|
68
|
+
| 6 | **Styling consistency** | Same visual thing built three ways — repeated rule blocks, one-off spacing/color literals that duplicate tokens, framework utilities fighting handwritten CSS. Consistency here is payload: one way to do X is the only way that stays small. (Design direction itself is evidence-led-ui's call.) |
|
|
69
|
+
|
|
70
|
+
### 4. Rank by user impact, fix the top, not all
|
|
71
|
+
|
|
72
|
+
| Severity | Meaning |
|
|
73
|
+
|---|---|
|
|
74
|
+
| **Critical** | Blocks or breaks: startup counted in tens of seconds, OOM crashes, multi-second UI freezes, a leak that kills a session in minutes |
|
|
75
|
+
| **High** | User-perceivable degradation: sluggish interactions, fan-spinning idle CPU, RAM that climbs over a workday, zombie processes accumulating across runs, slowest paths 2–10× slower than they should be |
|
|
76
|
+
| **Medium** | Waste with symptoms at scale: bundle bloat, N+1 under load, unbounded caches, missing pagination, duplicate dependencies |
|
|
77
|
+
| **Low** | Hygiene without a measured symptom: dead code, dead styles, micro-tuning. Do these when adjacent to a real fix, never instead of one. |
|
|
78
|
+
|
|
79
|
+
Fix the few that measurement actually implicates — three to five, rarely more. Each fix records its baseline number first. Prefer removing work over hiding it (delete the eager import beats code-splitting it beats deferring it), and prefer the platform primitive over a hand-rolled one.
|
|
80
|
+
|
|
81
|
+
### 5. Verify the fix
|
|
82
|
+
|
|
83
|
+
Re-measure exactly how you baselined, same machine, same data, cold and warm. A fix you did not measure is a hypothesis. For memory: cycle the changed path many times, force GC where the runtime allows (`--expose-gc`, DevTools), and compare committed memory — flat wins, sawtooth is fine, climbing is not fixed. If the number did not move, revert and say so; a change that adds complexity without moving the number is a regression.
|
|
84
|
+
|
|
85
|
+
### 6. Leave a guard behind
|
|
86
|
+
|
|
87
|
+
One check so it cannot silently return: bundle-size budget in CI, Lighthouse CI or `size-limit` for web, a slow-query threshold, a repeated-cycle memory assertion where feasible, a test that fails if the eager import returns. One gate beats good intentions.
|
|
88
|
+
|
|
89
|
+
### 7. Report
|
|
90
|
+
|
|
91
|
+
- Lead with numbers: what moved, X → Y, on which machine/data/date.
|
|
92
|
+
- Then remaining findings, ranked, each with file/line and the fix.
|
|
93
|
+
- Then what was **not checked** — unmeasured areas, stacks skipped, environments unavailable. A report that silently skips the mobile client or the batch job reads as complete coverage.
|
|
94
|
+
- Then what you changed vs. what you recommend and did not do.
|
|
95
|
+
- Label every claim `RUNTIME` / `CODE` / `DEDUCED` / `SNAPSHOT`. Include your false positives — candidates you investigated and dropped — so the survivor list is not hiding its noise.
|
|
96
|
+
|
|
97
|
+
## Honesty rules
|
|
98
|
+
|
|
99
|
+
- Never state or imply the software is "fast", "optimized", or "leak-free". State what was measured, fixed, and left unchecked.
|
|
100
|
+
- Never present a lint rule, bundle analyzer, or profiler as proof of the absence of problems; tools find a minority of what matters.
|
|
101
|
+
- Never invent a number, threshold, or version. If the claim is date-sensitive and unverified, mark it `SNAPSHOT` or say "verify this".
|
|
102
|
+
- "I could not measure this" is a legitimate and useful output. A fabricated confirmation is not.
|
|
103
|
+
- If the project is a prototype with no users and no load, say that proportionality applies — five real fixes beat forty ignored ones — and stop early.
|
|
104
|
+
|
|
105
|
+
## Reference map
|
|
106
|
+
|
|
107
|
+
Resolve every path from the installed skill root. Load only what the profile triggered.
|
|
108
|
+
|
|
109
|
+
- `references/playbooks.md` — per-stack sweeps and measurement commands: web frontend (Core Web Vitals with official thresholds), Node/backend/API, Electron, Tauri, mobile, native/compiled (Rust, C/C++, Go, JVM), Python, data & queries, and the payload/dead-weight/styling-consistency tooling. Read the sections the profile triggered.
|
|
110
|
+
- `references/memory-and-processes.md` — the leak catalog by pattern, detection technique per runtime (three-snapshot, allocation timeline, heap dumps, pprof, valgrind, Instruments, LeakCanary), component-framework leak rules, and the process lifecycle playbook: zombies, orphans, signal handling, process-tree kills, container PID 1, startup sweeps, leaked fds/ports/temp files. Read for any memory or process finding.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Lean — memory & processes
|
|
2
|
+
|
|
3
|
+
The deep reference for two of the six sweep areas: memory (leaks and hogging) and process lifecycle (zombies, orphans, shutdown). Read for any finding in those areas.
|
|
4
|
+
|
|
5
|
+
## Part 1 — Memory
|
|
6
|
+
|
|
7
|
+
### The leak taxonomy
|
|
8
|
+
|
|
9
|
+
Every memory leak is one of a small number of shapes. Name the shape before hunting the instance:
|
|
10
|
+
|
|
11
|
+
1. **Forgotten teardown** — a timer, listener, observer, subscription, or callback registered against something long-lived (window, document, a global emitter, an event bus, a message broker) and never removed. The registration itself keeps the owner object — and everything it captures — alive.
|
|
12
|
+
2. **Detached-but-referenced** — DOM nodes (or view/widget objects) removed from the document but still held by a closure, array, cache, or map. The GC cannot free what a live reference pins; "removed from the screen" is not "freed".
|
|
13
|
+
3. **Unbounded accumulation** — a cache, map, array, or queue that only grows. Not a leak by accident — a design that forgot limits. Includes "in-memory session store" with no eviction and metrics maps keyed by unbounded cardinality (per-request keys are the classic).
|
|
14
|
+
4. **Captured scope** — a long-lived closure captures a large object it doesn't need (a handler that uses one field but closes over the whole request/state). Also: promises that never settle, pinning everything their closures captured.
|
|
15
|
+
5. **Cycles in non-GC runtimes** — Rust `Rc`/`Arc` cycles, C++ shared_ptr loops, Objective-C retain cycles (delegate + strong reference both ways). The reference count never reaches zero. Break the cycle with `Weak` on one edge.
|
|
16
|
+
6. **Resource handles** — file descriptors, sockets, database connections, locks, temp files. Not heap, but the same symptom ("it dies after running a while") and the same rule: every acquisition has an owner that releases it on all paths.
|
|
17
|
+
|
|
18
|
+
### Hogging is not leaking
|
|
19
|
+
|
|
20
|
+
Flat-but-too-big is the other half. Hunt: whole files/datasets loaded to process item-by-item (stream instead); images decoded at full resolution for thumbnail-sized display (decode down, cache the small one); the same large data duplicated across processes/IPC boundaries (send references or deltas); logs and metrics buffered in RAM without a cap; caches sized by hope instead of measurement ("it'll fit"). In containers, set memory limits (cgroups, `--memory`, K8s requests/limits) so hogging surfaces as a chosen error instead of silent neighbor-starvation.
|
|
21
|
+
|
|
22
|
+
### Detection technique
|
|
23
|
+
|
|
24
|
+
**The universal method:** run the suspected loop many times (open/close the view, iterate the endpoint, replay the job), force GC where possible, and compare committed memory between cycles. Flat across cycles = no leak. Sawtooth returning to baseline = GC, not a leak. Climbing staircase = leak. Sample `process.memoryUsage()` (Node), RSS via `ps`/`top`, or the runtime's counter, every N cycles, and log the series — a leak you can graph is a leak you can bisect. Change one thing between runs.
|
|
25
|
+
|
|
26
|
+
**JavaScript/TypeScript (browser and Node):**
|
|
27
|
+
|
|
28
|
+
- **Three-snapshot technique** (Chrome DevTools Memory): snapshot → perform the suspected leaky action several times → snapshot → force GC, act again, force GC → snapshot. Objects present in snapshot 3 that grew in count between snapshots 2 and 3 are your leak; the retainer chain shows what pins them.
|
|
29
|
+
- **Allocation instrumentation on timeline** records every allocation — blue bars that never get collected mark the leak as it happens.
|
|
30
|
+
- `queryObjects(constructor)` in the console counts live instances; Detached nodes filter in heap snapshots for removed-but-pinned DOM.
|
|
31
|
+
- Node: `node --inspect` + DevTools heap snapshots; `clinic heap` for guided diagnosis; `--expose-gc` in tests so assertions can GC before measuring. Production-safe heap snapshot on signal where you control the entrypoint.
|
|
32
|
+
- The usual suspects, in order of frequency: forgotten `setInterval` (worse than `setTimeout` — it never stops on its own), listeners on long-lived objects added per-mount/per-request, `ResizeObserver`/`IntersectionObserver`/`MutationObserver` never `disconnect()`ed, growing `Map`s used as caches, detached nodes held in module-level arrays, per-request closures stored on a global.
|
|
33
|
+
|
|
34
|
+
**The unified cleanup pattern** — register everything against one handle and teardown once:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const ac = new AbortController();
|
|
38
|
+
window.addEventListener("resize", onResize, { signal: ac.signal });
|
|
39
|
+
fetch(url, { signal: ac.signal }).then(/* ... */);
|
|
40
|
+
const ro = new ResizeObserver(onResize); ro.observe(el);
|
|
41
|
+
// one teardown path (effect cleanup, session close, SIGTERM handler):
|
|
42
|
+
ac.abort(); ro.disconnect(); clearInterval(id);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Web-platform APIs accept `AbortSignal` directly; the rest get disconnected in the same teardown function. One owner, one path — including the error path.
|
|
46
|
+
|
|
47
|
+
**Component frameworks (React and kin):** every subscription started in an effect is returned-from that effect for cleanup, no exceptions; stores and event buses get unsubscribe on unmount; beware module-level singletons accumulating per-component state (registered callbacks never removed — the leak lives on after the component dies). Long lists get virtualized. Before adding `memo`/`useMemo` anywhere, catch a real re-render in the Profiler — memoization has its own memory cost and is frequently perf theater. Watch `key` misuse: index keys on reorder-prone lists cause remount storms (CPU) and stale-capture bugs (memory).
|
|
48
|
+
|
|
49
|
+
**Rust / C / C++ / Go / JVM / Python:** see the native/compiled and Python sections of `references/playbooks.md` for the per-runtime tools (valgrind/ASan/LSan, heaptrack, pprof, async-profiler/JFR, tracemalloc). The cycle shapes to hunt are listed in the taxonomy above.
|
|
50
|
+
|
|
51
|
+
### Rules for fixes
|
|
52
|
+
|
|
53
|
+
Fix the lifetime, not the symptom: remove the registration (or disconnect the observer) at the source that created it; bound the cache with an eviction policy (LRU/TTL) instead of deleting entries manually where it keeps growing; break cycles at the design level (`Weak`/`weakref`/unowned edge) rather than sprinkling cleanups. Then re-run the cycle test and show the flat line. A "fix" without the flat line is not a fix.
|
|
54
|
+
|
|
55
|
+
## Part 2 — Processes & lifecycle
|
|
56
|
+
|
|
57
|
+
### Zombies vs orphans
|
|
58
|
+
|
|
59
|
+
- A **zombie** is a dead child the parent never reaped — it holds a PID and a kernel exit-status slot. Too many exhaust the process table. On Unix, only the parent's `wait()`/`waitpid()` (or equivalent) clears it. **Rust: dropping `Child` does not reap it — you must `wait()`.** Go: `cmd.Wait()`. C: `waitpid`. Node gets an `exit` event automatically — your job is not to spawn what you can't track. A parent that never reaps is itself the bug; the zombies are the receipt.
|
|
60
|
+
- An **orphan** is a child whose parent died first. It keeps running, reparented to init — nobody is coming to shut it down. Orphans are what users call "why is this still running after I quit?".
|
|
61
|
+
|
|
62
|
+
### Kill the tree, not the node
|
|
63
|
+
|
|
64
|
+
`kill(pid)` kills one process; its spawned children (MCP servers, LSPs, shells, helpers) survive as orphans. Correct patterns:
|
|
65
|
+
|
|
66
|
+
- **Never kill the host you run in.** Before killing any long-lived daemon, node process, or "orphan", trace its ancestry (`ps -o pid,ppid,command` up the PPID chain) and check it is not your own host or an ancestor of it — agent sessions live *inside* a host daemon process, so a session killing that daemon kills itself mid-turn, and a child killing its parent kills the whole app's sessions. A process that is merely using lots of memory is a measurement finding, not a kill target; report it. Live-session agents do not kill host daemons at all — orphan cleanup belongs to the host's startup sweep (below), never to a session that might be running inside the thing it aims at.
|
|
67
|
+
- **Unix:** start the child in its own process group (`detached: true` in Node, `setsid`/`process_group` elsewhere), then kill the group: `process.kill(-pid, sig)` — the negative PID addresses the whole group. Escalate SIGTERM → grace period → SIGKILL.
|
|
68
|
+
- **Windows:** there are no process groups; `taskkill /PID <pid> /T /F` kills the tree (`/T` = tree, `/F` = force), or use a Job Object assigned to children so closing the handle terminates them all.
|
|
69
|
+
- **Both:** kill children *before* the parent exits, in order — parents can't clean up after they're dead; and children of an interactive app must die when the app does, normal exit *and* crash.
|
|
70
|
+
|
|
71
|
+
### Graceful shutdown is a feature
|
|
72
|
+
|
|
73
|
+
On SIGTERM/SIGINT (and before-exit hooks): stop accepting new work, let in-flight work finish or checkpoint it, kill the child tree (above), close sockets/DB connections, release locks and port registrations, remove pidfiles/ledgers, flush and close logs — with a deadline, then force-exit. Ctrl+C on a dev server leaving a port busy is this feature missing. Test it: send SIGTERM, assert nothing from your app survives (`ps`, `lsof -i :<port>`).
|
|
74
|
+
|
|
75
|
+
### Crash leftovers: the startup sweep
|
|
76
|
+
|
|
77
|
+
Processes crash; whatever they left must not outlive the next boot. Pattern: on start, read a ledger of resources you own (pidfiles with PID + start-time to avoid PID reuse, registered ports, lock files under `tmpdir`), verify each is actually one of yours, kill the stale ones, then write your own entry. Flock/`O_EXCL` locks make "is the old one really dead?" checkable rather than guessed. Temp dirs get a sweep of your app's namespaced files on start. This is cheap insurance and the fix for "every crash leaves another zombie until reboot".
|
|
78
|
+
|
|
79
|
+
### Containers: the PID 1 problem
|
|
80
|
+
|
|
81
|
+
If your process is PID 1 in a container, it inherits orphaned zombies and default signal handlers that ignore SIGTERM. Either run a proper init (`docker run --init`, tini, dumb-init) or handle it yourself: reap children, trap and act on SIGTERM. K8s does not save you from this — exec-form ENTRYPOINT still makes you PID 1.
|
|
82
|
+
|
|
83
|
+
### Leaked handles and files
|
|
84
|
+
|
|
85
|
+
The slow cousins of zombie processes: file descriptors (`lsof -p <pid>` — a climbing count is a leak), sockets/ports held by dead listeners (`ss -ltnp` / `lsof -i`), lock files, and temp files that outlive their writers. Every open() has a matching close() on all paths — `finally`, defer, RAII, context managers — and temp files are created with your app's namespaced prefix so a startup sweep can find them.
|
|
86
|
+
|
|
87
|
+
### The verification loop
|
|
88
|
+
|
|
89
|
+
1. Start the app; record `ps`/RSS/fd count for the process tree.
|
|
90
|
+
2. Exercise the suspected path N times (open/close, request, job run).
|
|
91
|
+
3. Quit — normal exit and SIGKILL both.
|
|
92
|
+
4. Assert: nothing from your tree remains (`ps`, port free, fd count back to baseline, temp dir clean), and RSS on next start matches the first start.
|
|
93
|
+
|
|
94
|
+
Anything that survives step 4 is the finding, and the ledger/sweep/group-kill patterns above are the fix.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
**Provenance:** snapshot 17 August 2026. Sources: Rust std `process::Child` documentation (zombies and reaping), Node.js `child_process` documentation (detached/process-group semantics on Unix and Windows), Docker/tini PID 1 reaping guidance, Chrome DevTools memory documentation (three-snapshot technique, allocation timeline, `queryObjects`), web.dev long-task and lifecycle guidance. OS signal semantics are stable; tool flags and library APIs decay — re-verify specifics with web access before asserting.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Lean — per-stack playbooks
|
|
2
|
+
|
|
3
|
+
Load only the sections the profile triggered. Commands assume a POSIX shell unless noted. Claims sourced on the snapshot date (17 August 2026) carry `SNAPSHOT`; tool versions and thresholds decay — re-verify with web access before asserting as current.
|
|
4
|
+
|
|
5
|
+
## Web frontend
|
|
6
|
+
|
|
7
|
+
**Targets (official web.dev stable thresholds, measured at p75, mobile and desktop split):**
|
|
8
|
+
|
|
9
|
+
| Metric | Good | Needs improvement | Poor |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| LCP (Largest Contentful Paint) | ≤ 2.5s | ≤ 4.0s | > 4.0s |
|
|
12
|
+
| INP (Interaction to Next Paint) | ≤ 200ms | ≤ 500ms | > 500ms |
|
|
13
|
+
| CLS (Cumulative Layout Shift) | ≤ 0.1 | ≤ 0.25 | > 0.25 |
|
|
14
|
+
|
|
15
|
+
SEO blogs circulate claims of a March 2026 tightening of LCP to 2.0s (`SNAPSHOT` — could not be confirmed on web.dev at snapshot time). Treat 2.0s as an aspiration, not a threshold; verify before quoting either number to a user.
|
|
16
|
+
|
|
17
|
+
**Measure:** Lighthouse (DevTools or `lighthouse https://x --output json` in CI), Chrome DevTools Performance tab for long tasks, Network waterfall for request chains, Coverage tab for shipped-but-unused JS/CSS, `web-vitals` npm package for RUM field data. Lighthouse CI or `size-limit` as the regression gate.
|
|
18
|
+
|
|
19
|
+
**Symptom → usual cause:**
|
|
20
|
+
|
|
21
|
+
| Symptom | Usual causes | Fixes |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Slow LCP | Oversized hero image, render-blocking CSS/JS, slow TTFB, web-font swap | AVIF/WebP + `srcset`, explicit dimensions, `fetchpriority="high"` on the LCP image, preload the font + `font-display: swap` (subset it), inline critical CSS / defer the rest, fix server TTFB first if > ~400–600ms — no frontend work survives that |
|
|
24
|
+
| Poor INP | Long tasks (>50ms) on the main thread, expensive handlers, layout thrash, hydration weight | Split long tasks (`scheduler.yield()` where available, else task chunking), debounce expensive input handlers, batch DOM reads before writes, animate only `transform`/`opacity`, move heavy compute to a web worker, ship less JS |
|
|
25
|
+
| High CLS | Images/embeds without dimensions, late banners pushing content, font swap | Width/height or `aspect-ratio` on all media, reserve ad/banner slots (`min-height`), `content-visibility` for below-fold, avoid injecting above existing content |
|
|
26
|
+
| Slow nav | Waterfall fetches, client-side everything, no prefetch | Parallelize with `Promise.all`, prefetch likely-next routes, partial/staged rendering, keep-alive connections |
|
|
27
|
+
|
|
28
|
+
**Sweep list:** code splitting at routes (`React.lazy`/dynamic `import()`), tree-shaking blockers (side-effectful modules, CJS in the graph), image audit (format, dimensions, `loading="lazy"` + `decoding="async"` below fold), font count and subsetting, dependency weight (bundle analyzer: `source-map-explorer`, `rollup-plugin-visualizer`, `webpack-bundle-analyzer`), virtualized long lists, memoization only where the React DevTools Profiler showed a real re-render cost — memo-by-default is perf theater, context split instead of one giant provider, `passive: true` listeners for scroll/touch, debounced resize/search handlers, service worker caching where offline or repeat visits matter.
|
|
29
|
+
|
|
30
|
+
## Node.js / backend / API
|
|
31
|
+
|
|
32
|
+
**Measure:** `autocannon` or `k6` for load (watch p99, not the average — the average lies), `clinic doctor` / `clinic flame` / `0x` for CPU and event-loop diagnosis, `--inspect` + Chrome DevTools for heap. DB: slow-query log, `EXPLAIN ANALYZE`.
|
|
33
|
+
|
|
34
|
+
**Sweep list:**
|
|
35
|
+
|
|
36
|
+
- **Event-loop blocking:** sync fs/crypto/zlib in request handlers, `JSON.parse` of huge payloads on the hot path, regex backtracking. Move to workers or streams.
|
|
37
|
+
- **N+1 queries:** one join/include/dataloader instead of a loop of queries. The most common backend bottleneck, by far.
|
|
38
|
+
- **Missing indexes:** every frequent filter/sort column; verify with `EXPLAIN ANALYZE` that the plan uses them.
|
|
39
|
+
- **Unpaginated reads:** `SELECT *` on growing tables, `findMany()` without `take`. Cursor pagination for stable ordering.
|
|
40
|
+
- **Connection pools:** sized for the DB's real limit; check for pool exhaustion under load (requests queueing on a connection).
|
|
41
|
+
- **Caching with bounds:** TTL or LRU on expensive derivations; invalidate on write. Cache stampede guard (lock or stale-while-revalidate) when a hot key expires.
|
|
42
|
+
- **Payload:** gzip/brotli on responses, HTTP/2+ or keep-alive, avoid re-serializing the same object per request.
|
|
43
|
+
- **Memory ceiling:** `--max-old-space-size` matched to the container limit so GC pressure shows up as errors you chose, not an OOM kill at a random allocation.
|
|
44
|
+
- **Retries:** capped, with backoff and jitter; unbounded retry loops are a self-inflicted outage plus a memory leak (each attempt holds state).
|
|
45
|
+
|
|
46
|
+
## Electron
|
|
47
|
+
|
|
48
|
+
Official maintainer guidance (electronjs.org performance tutorial, `SNAPSHOT`): profile, then fix the most resource-hungry thing; repeat. VS Code and Slack got fast exactly this way.
|
|
49
|
+
|
|
50
|
+
**Sweep list:**
|
|
51
|
+
|
|
52
|
+
- **Lazy `require`:** Node modules loaded at startup cost startup forever. Require at first use for heavy/rare paths; defer expensive setup with idle-time initialization.
|
|
53
|
+
- **Price modules before adopting:** `node --cpu-prof --heap-prof -e "require('mod')"` — the canonical example is a "simple" connectivity checker that parsed a 100k-line JSON port list at load. Server-oriented modules are often wrong for desktop.
|
|
54
|
+
- **Never block the main process:** UI jank and dead IPC come from main-process busy work. CPU-heavy work goes to utility processes / worker threads; keep main for orchestration.
|
|
55
|
+
- **Bundle renderer code** (bundler or esbuild) instead of hundreds of module loads at window open.
|
|
56
|
+
- **Window hygiene:** lazy-create `BrowserWindow`s, destroy (not just hide) windows whose content is expensive and rarely revisited, `process.getProcessMemoryInfo()` per process to find which side eats.
|
|
57
|
+
- **Tray/menu/global-shortcut listeners** registered once, removed on app quit; background throttling is default — don't defeat it with busy polling (`powerSaveBlocker` only while genuinely needed).
|
|
58
|
+
- **Startup:** `Menu.setApplicationMenu(null)` when no menu is needed; splash/deferred window show to cut time-to-visible; V8 compile cache for large renderer bundles.
|
|
59
|
+
- Security config (`contextIsolation`, sandbox) is bulletproof's lane — but note sandboxing also shrinks renderer memory; do not weaken it for speed.
|
|
60
|
+
|
|
61
|
+
## Tauri
|
|
62
|
+
|
|
63
|
+
**Sweep list:**
|
|
64
|
+
|
|
65
|
+
- **Release profile:** in `Cargo.toml` `[profile.release]` — `lto = true` (or `"thin"`), `codegen-units = 1`, `strip = true`; `panic = "abort"` if acceptable. `opt-level = "s"/"z"` trades speed for size — measure which you need.
|
|
66
|
+
- **IPC cost:** every `invoke` serializes with serde — don't shuttle large blobs or big JSON back and forth per keystroke; chunk, delta, or move the work to the Rust side. Watch for per-frame IPC from frontend animation/monitoring loops.
|
|
67
|
+
- **State:** `tauri::State` with `Mutex` held across `.await` serializes everything behind it; scope locks tightly.
|
|
68
|
+
- **Frontend** follows the web section exactly — the webview is a browser; bundle size and long tasks hit the same.
|
|
69
|
+
- **Assets:** embed vs. fetch per asset class; large binaries should not ship inside the binary if they can be fetched/unpacked on demand.
|
|
70
|
+
- **Plugins:** lazy-init heavy plugins; each one is startup cost on the Rust and JS side both.
|
|
71
|
+
- **Measure:** `cargo bloat` / `cargo tree -d` for binary weight and duplicate deps; standard Rust profilers (`perf`, Instruments, `cargo-flamegraph`) for hot paths.
|
|
72
|
+
|
|
73
|
+
## Mobile
|
|
74
|
+
|
|
75
|
+
**Sweep list:** cold-start path (lazy screen registration, defer non-critical SDK init — analytics can wait), list virtualization (`FlatList`/`RecyclerView`/`LazyColumn` — never render 1000 rows), image assets per density via asset catalogs (not runtime-downscaled full images), main-thread discipline (decode/parse off the main thread), memory-warning handling that actually drops caches.
|
|
76
|
+
|
|
77
|
+
**Measure/leak tools:** Android — Android Studio Profiler, `LeakCanary` for lifecycle leaks, `dumpsys meminfo`; iOS — Instruments Allocations/Leaks, Xcode memory graph debugger. Responding to memory warnings by freeing caches is table stakes on both.
|
|
78
|
+
|
|
79
|
+
## Native / compiled
|
|
80
|
+
|
|
81
|
+
- **Rust:** leaks are usually `Rc`/`Arc` cycles (switch one direction to `Weak`), `Box::leak`, unbounded channels, or tasks blocked forever holding state. Blocking calls inside async runtime threads stall the executor — use `spawn_blocking`. Measure: `cargo-flamegraph`, `heaptrack`, `pprof` crate. Children must be `wait()`ed — dropping a `Child` does not reap it (see `references/memory-and-processes.md`).
|
|
82
|
+
- **C/C++:** every `malloc`/`new`/`fopen` has an owner that frees/closes on all paths — RAII or scope guards, not discipline. Measure: valgrind memcheck/massif, AddressSanitizer/LeakSanitizer (`-fsanitize=address,leak`), `heaptrack`.
|
|
83
|
+
- **Go:** goroutine leaks — a goroutine blocked on a channel/ctx that never arrives holds everything it captured forever. `pprof` goroutine + heap profiles tell you both. Set `GOMEMLIMIT` in containers; tune `GOGC` only after measuring.
|
|
84
|
+
- **JVM:** bound the heap (`-Xmx`) to the container, watch for unbounded caches and listener registries; `jmap -histo`, async-profiler, JFR for allocation sites.
|
|
85
|
+
- **Games/hot loops:** frame budget is 16.6ms @60 (8.3ms @120) including everything. No per-frame allocation (object pools), no per-frame sync I/O, no GC spikes mid-frame; batch draws; time-slice background work.
|
|
86
|
+
|
|
87
|
+
## Python
|
|
88
|
+
|
|
89
|
+
Generators/streams instead of list-building for large data; vectorize hot loops (NumPy/pandas — or Polars for large frames) instead of Python-level iteration; never block the asyncio event loop with sync I/O or CPU work (offload to processes); `functools.lru_cache` is bounded — `cached_property` and hand-rolled dict caches are not. Measure: `tracemalloc` for allocation deltas, `memory_profiler` line-level, `py-spy` for live flamegraphs without stopping the process. Watch for reference cycles keeping big objects alive when `gc` is disabled or timing-dependent.
|
|
90
|
+
|
|
91
|
+
## Data & queries (any stack)
|
|
92
|
+
|
|
93
|
+
`EXPLAIN (ANALYZE)` the slow ones; indexes on frequent filters/sorts — but every index taxes writes, so measure both sides. Batch writes; avoid N single-row inserts inside a transaction per row. Cursor/keyset pagination over offset for deep pages. Slow-query log threshold low enough to catch regressions in CI-like environments. Cache expensive reads with explicit invalidation, not hope.
|
|
94
|
+
|
|
95
|
+
## Payload & dead weight (all stacks)
|
|
96
|
+
|
|
97
|
+
`SNAPSHOT` (17 Aug 2026): **Knip** is the standard JS/TS dead-code finder — unused files, exports, dependencies, and devDependencies across monorepo workspaces; `depcheck` is the older alternative. CSS: PurgeCSS (or the framework's built-in pruning) against real markup — beware class names built dynamically, which purgers cannot see; guard with a safelist. Shipped-code audit: DevTools Coverage for what the browser actually ran.
|
|
98
|
+
|
|
99
|
+
**Sweep list:** `knip` in CI; duplicate dependencies (`pnpm why <pkg>`, `npm ls <pkg>`) — two versions of one library is double weight; "two of the same job" audit (two icon sets, two date libs, two CSS systems, a utility lib plus hand-rolled copies of its functions); polyfills for browsers no longer supported; debug/symbol payloads shipped in release (strip; source maps to a symbol server, not the bundle); largest-files audit (`du`, bundle analyzer) — the top ten files are usually the whole story; unused assets in repos (images, fonts nobody references).
|
|
100
|
+
|
|
101
|
+
## Styling consistency (payload view)
|
|
102
|
+
|
|
103
|
+
The rule: **one way to express one visual decision.** Hunt repeated rule blocks that differ by one value, spacing/color literals that duplicate existing design tokens, the same component styled three ways, utility classes wrapped around handwritten CSS doing the same job, dead rules for removed components. Each duplication is bytes today and divergence tomorrow. Kill the copies, keep the token. If resolving it requires a design *decision* (which of three styles is right), that call belongs to evidence-led-ui — coordinate rather than decide unilaterally.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
**Provenance:** snapshot 17 August 2026. Sources: web.dev Web Vitals (stable LCP/INP/CLS thresholds), Electron official performance tutorial (module cost, lazy loading, main-process blocking, profiling guidance), Rust std `process::Child` docs (zombie reaping), Knip documentation and 2026 ecosystem coverage (dead-code standard claim — `SNAPSHOT`), Valgrind/LeakCanary/Instruments/pprof public docs for tool usage. Version-specific flags and thresholds decay fastest; re-verify before asserting.
|
package/dist/core/skills.js
CHANGED
|
@@ -123,7 +123,7 @@ export function formatSkillsForPrompt(skills) {
|
|
|
123
123
|
.join("\n");
|
|
124
124
|
return (`## Skills\n\n` +
|
|
125
125
|
`Before acting, compare the user's request with every skill description below. ` +
|
|
126
|
-
`When the request
|
|
126
|
+
`When the request — or the work itself, mid-build — enters a skill's scope, invoke it with the **skill** tool before making decisions or edits; loaded content routes between build-time and review modes. ` +
|
|
127
127
|
`Respect explicit exclusions in the description. Matching skill instructions specialize this prompt but do not override project or file/module rules.\n\n` +
|
|
128
128
|
`Match the work, not the topic: a skill's subject matter appearing in the request is not a match when the actual change falls outside its scope. ` +
|
|
129
129
|
`Skip the skill when the task is routine, narrow, or already covered by existing patterns in the codebase \u2014 an unnecessary invocation costs context and slows the task. ` +
|
package/dist/core/skills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/skill.js
CHANGED
|
@@ -38,6 +38,7 @@ function generateSkillDescription(skills) {
|
|
|
38
38
|
.join("\n");
|
|
39
39
|
return (`Invoke a skill by name to get specialized instructions for a task. ` +
|
|
40
40
|
`Before acting, invoke a skill when the request matches its scope and respect explicit exclusions. ` +
|
|
41
|
+
`Invoke as soon as the work enters a skill's scope — while building or when checking — not only for reviews. ` +
|
|
41
42
|
`Match the work rather than the topic, skip it for routine or narrow changes, and do not re-invoke a skill already loaded in this conversation.\n\n` +
|
|
42
43
|
`Available skills:\n${list}`);
|
|
43
44
|
}
|
package/dist/tools/skill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IAC7D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;CACpF,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,uEAAuE;IACvE,qEAAqE;IACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,wBAAwB,CAAC,MAAM,CAAC;QAC7C,UAAU;QACV,KAAK,CAAC,OAAO,CAAC,KAAK;YACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YACtD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvD,OAAO,iBAAiB,KAAK,CAAC,KAAK,kCAAkC,SAAS,IAAI,MAAM,EAAE,CAAC;YAC7F,CAAC;YAED,MAAM,KAAK,GAAG,CAAC,wBAAwB,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;YACvD,IAAI,KAAK,CAAC,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,yBAAyB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YAC9C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,KAAK,CAAC,IAAI,CACR,yLAAyL,CAC1L,CAAC;YACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAe;IAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,4DAA4D,CAAC;IACtE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,WAAW,IAAI,gBAAgB,EAAE,CAAC;SACnE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,CACL,qEAAqE;QACrE,oGAAoG;QACpG,oJAAoJ;QACpJ,sBAAsB,IAAI,EAAE,CAC7B,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;IAC7D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;CACpF,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,uEAAuE;IACvE,qEAAqE;IACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,wBAAwB,CAAC,MAAM,CAAC;QAC7C,UAAU;QACV,KAAK,CAAC,OAAO,CAAC,KAAK;YACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YACtD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvD,OAAO,iBAAiB,KAAK,CAAC,KAAK,kCAAkC,SAAS,IAAI,MAAM,EAAE,CAAC;YAC7F,CAAC;YAED,MAAM,KAAK,GAAG,CAAC,wBAAwB,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;YACvD,IAAI,KAAK,CAAC,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,yBAAyB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YAC9C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,KAAK,CAAC,IAAI,CACR,yLAAyL,CAC1L,CAAC;YACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAe;IAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,4DAA4D,CAAC;IACtE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,WAAW,IAAI,gBAAgB,EAAE,CAAC;SACnE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,CACL,qEAAqE;QACrE,oGAAoG;QACpG,8GAA8G;QAC9G,oJAAoJ;QACpJ,sBAAsB,IAAI,EAAE,CAC7B,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenkaiiii/ggcoder",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.46.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI coding agent with OAuth authentication for Anthropic, OpenAI, and Gemini",
|
|
6
6
|
"license": "MIT",
|
|
@@ -115,9 +115,9 @@
|
|
|
115
115
|
"typescript-language-server": "^5.3.0",
|
|
116
116
|
"wrap-ansi": "^10.0.0",
|
|
117
117
|
"zod": "^4.4.3",
|
|
118
|
-
"@kenkaiiii/gg-
|
|
119
|
-
"@kenkaiiii/gg-
|
|
120
|
-
"@kenkaiiii/gg-
|
|
118
|
+
"@kenkaiiii/gg-agent": "5.46.1",
|
|
119
|
+
"@kenkaiiii/gg-ai": "5.46.1",
|
|
120
|
+
"@kenkaiiii/gg-core": "5.46.1"
|
|
121
121
|
},
|
|
122
122
|
"optionalDependencies": {
|
|
123
123
|
"@huggingface/transformers": "^3.6.0",
|