Installs into .claude/skills of the current project.
Are you the author of Sql Pro?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/harmitx7-sql-pro)
---
name: sql-pro
description: "Use when designing schemas, querying, indexing, optimizing, and securing sql pro databases and data models."
version: 6.0.0
last-updated: 2026-09-29
skills:
- database-design
- db-latency-auditor
- supabase-postgres-best-practices
tools: Read, Grep, Glob, Bash, Edit, Write
scripts-binding:
- .agent/scripts/lint_runner.js
- .agent/scripts/verify_all.js
---
# SQL Pro β Advanced Query & Schema Mastery
## Mandatory Pre-Flight Context Inspection
Before reading, generating, or refactoring code in the `sql-pro` domain, inspect these 5 critical parameters:
1. **System Boundaries & Dependencies**: Verify that all required dependencies exist in target package manifests and environment paths.
2. **Runtime Context & Platform Invariants**: Confirm target platform constraints (Node.js, Browser, Mobile OS, Edge runtime) before applying APIs.
3. **Execution Guardrails**: Identify potential side-effects, state mutations, and unhandled asynchronous exceptions.
4. **Validation & Type Contracts**: Validate input data schemas and strict type constraints across all module interfaces.
5. **Observability & Proof of Execution**: Ensure execution produces tangible verification signals (terminal output, tests, metrics).
## Activation Boundaries
- **Activate when:** Use when designing schemas, querying, indexing, optimizing, and securing sql pro databases and data models.
- **DO NOT activate when:** The task falls outside the `sql-pro` domain or is managed by a different dedicated specialist agent.
## π Multi-Pass Execution Protocol
| Pass | Phase | Core Action | Adaptive Depth |
|:---|:---|:---|:---|
| **Pass 1** | **Understand** | Deconstruct the user's explicit objective, implicit requirements, and platform constraints. | Fast / Standard / Deep |
| **Pass 2** | **Plan** | Decompose task into smallest logical steps; map dependencies, affected files, and tool calls. | Standard / Deep |
| **Pass 3** | **Execute** | Implement solution with production-grade craft, zero placeholders, and strict typing. | All Modes |
| **Pass 4** | **Verify** | Run linters, unit tests, or compiler checks to validate structural correctness. | All Modes |
| **Pass 5** | **Attack & Falsify** | Perform adversarial search for edge-case failures, counterexamples, race conditions, and traps. | Standard / Deep |
| **Pass 6** | **Harden** | Eliminate discovered friction, optimize performance, and harden error boundaries. | Standard / Deep |
| **Pass 7** | **Quality Gate** | Enforce Verification-Before-Completion (VBC) with concrete terminal proof before finalizing. | All Modes |
---
## π οΈ Technical Architecture & Reference Recipes
## 2026 SQL Performance & Query Invariants
1. **SARGable Date/Time Predicates**:
```sql
-- β BAD: Function on column kills index scan (Seq Scan)
WHERE DATE(created_at) = '2026-01-01'
-- β GOOD: Direct range comparison enables Index Scan
WHERE created_at >= '2026-01-01 00:00:00+00' AND created_at < '2026-01-02 00:00:00+00'
```
2. **Keyset Cursor Pagination (O(1) vs O(N) OFFSET)**:
```sql
-- β Instant lookup regardless of page depth
SELECT id, title, created_at
FROM articles
WHERE (created_at, id) < ($last_created_at, $last_id)
ORDER BY created_at DESC, id DESC
LIMIT 20;
```
3. **CTE Optimization (`AS NOT MATERIALIZED`)**: In PostgreSQL 12+, CTEs inline automatically unless marked `MATERIALIZED`. Explicitly control materialization when CTE contains heavy calculations.
4. **Batch Upserts with `ON CONFLICT`**:
```sql
INSERT INTO metrics (device_id, recorded_at, val)
VALUES ($1, $2, $3)
ON CONFLICT (device_id, recorded_at)
DO UPDATE SET val = EXCLUDED.val;
```
## Hallucination Traps (Read First)
- β String-concatenating user input into SQL β β Always use parameterized queries (`$1`, `?`)
- β Using `OFFSET 50000` for pagination β β Use keyset cursor pagination (`WHERE id > $last_id`)
- β Wrapping indexed columns in functions in WHERE clauses β β Compare bare column against computed value
- β `SELECT *` in production queries β β Select explicit columns to utilize covering indexes
- β `COUNT(*)` on millions of rows for simple existence check β β Use `SELECT EXISTS(SELECT 1 FROM ...)`
---
## Common Table Expressions (CTEs)
### Basic CTE
```sql
-- CTE for readability and reuse
WITH active_users AS (
SELECT id, name, email, created_at
FROM users
WHERE is_active = true
AND last_login > CURRENT_DATE - INTERVAL '30 days'
),
user_orders AS (
SELECT user_id, COUNT(*) AS order_count, SUM(total) AS total_spent
FROM orders
WHERE status = 'completed'
GROUP BY user_id
)
SELECT
u.name,
u.email,
COALESCE(o.order_count, 0) AS orders,
COALESCE(o.total_spent, 0) AS revenue
FROM active_users u
LEFT JOIN user_orders o ON u.id = o.user_id
ORDER BY revenue DESC;
```
### Recursive CTE (Hierarchical Data)
```sql
-- Org chart: find all reports under a manager
WITH RECURSIVE org_tree AS (
-- Base case: the starting manager
SELECT id, name, manager_id, 1 AS depth
FROM employees
WHERE id = 42 -- starting point
UNION ALL
-- Recursive case: find direct reports
SELECT e.id, e.name, e.manager_id, t.depth + 1
FROM employees e
INNER JOIN org_tree t ON e.manager_id = t.id
WHERE t.depth < 10 -- safety limit to prevent infinite loops
)
SELECT * FROM org_tree ORDER BY depth, name;
-- β HALLUCINATION TRAP: Always include a depth/cycle guard
-- Without it, circular references cause infinite recursion
-- PostgreSQL: use CYCLE detection clause (PG 14+)
-- SQL Server: use MAXRECURSION option
```
### CTE for Running Totals & Pagination
```sql
-- Keyset pagination (faster than OFFSET for large tables)
WITH page AS (
SELECT id, name, created_at
FROM products
WHERE (created_at, id) < (:last_created_at, :last_id) -- cursor
ORDER BY created_at DESC, id DESC
LIMIT 20
)
SELECT * FROM page;
-- β HALLUCINATION TRAP: OFFSET-based pagination gets slower with higher pages
-- OFFSET 100000, LIMIT 20 scans and discards 100,000 rows
-- Keyset pagination is O(1) regardless of page number
```
---
## Window Functions
### Ranking Functions
```sql
-- ROW_NUMBER: unique sequential number per partition
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept
FROM employees;
-- RANK vs DENSE_RANK
-- RANK: 1, 2, 2, 4 (gaps after ties)
-- DENSE_RANK: 1, 2, 2, 3 (no gaps)
SELECT
name,
score,
RANK() OVER (ORDER BY score DESC) AS rank,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank
FROM leaderboard;
-- NTILE: divide into N equal groups
SELECT
name,
revenue,
NTILE(4) OVER (ORDER BY revenue DESC) AS quartile
FROM companies;
```
### Aggregate Windows
```sql
-- Running total
SELECT
date,
amount,
SUM(amount) OVER (ORDER BY date) AS running_total,
AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg_7d
FROM daily_revenue;
-- Percentage of total
SELECT
category,
revenue,
ROUND(100.0 * revenue / SUM(revenue) OVER (), 2) AS pct_of_total
FROM category_sales;
-- Difference from previous row
SELECT
month,
revenue,
revenue - LAG(revenue) OVER (ORDER BY month) AS mom_change,
ROUND(100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
/ NULLIF(LAG(revenue) OVER (ORDER BY month), 0), 2) AS mom_pct_change
FROM monthly_revenue;
```
### Frame Clauses
```sql
-- Frame clause controls which rows the window function sees
SUM(amount) OVER (
ORDER BY date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW -- last 3 rows (physical)
)
SUM(amount) OVER (
ORDER BY date
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW -- last 7 days (logical)
)
-- ROWS vs RANGE:
-- ROWS = physical row count (exact)
-- RANGE = logical value range (handles ties differently)
-- β HALLUCINATION TRAP: Default frame is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-- This means SUM() OVER (ORDER BY x) includes ALL preceding rows, not just "the one before"
-- To get a true running count of N rows, use ROWS BETWEEN explicitly
```
### Lead / Lag Analysis
```sql
-- Next and previous values
SELECT
event_date,
user_id,
LAG(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS prev_visit,
LEAD(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS next_visit,
event_date - LAG(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS days_between
FROM user_events;
-- FIRST_VALUE / LAST_VALUE
SELECT
department,
name,
salary,
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary DESC) AS highest_paid,
LAST_VALUE(name) OVER (
PARTITION BY department ORDER BY salary DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- β οΈ required!
) AS lowest_paid
FROM employees;
-- β HALLUCINATION TRAP: LAST_VALUE without explicit frame clause returns CURRENT ROW
-- You MUST specify ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
```
---
## PIVOT / UNPIVOT / Conditional Aggregation
### PostgreSQL / Standard SQL (Conditional Aggregation)
```sql
-- PostgreSQL doesn't have PIVOT β use conditional aggregation
SELECT
product_name,
SUM(CASE WHEN quarter = 'Q1' THEN revenue ELSE 0 END) AS q1,
SUM(CASE WHEN quarter = 'Q2' THEN revenue ELSE 0 END) AS q2,
SUM(CASE WHEN quarter = 'Q3' THEN revenue ELSE 0 END) AS q3,
SUM(CASE WHEN quarter = 'Q4' THEN revenue ELSE 0 END) AS q4,
SUM(revenue) AS total
FROM quarterly_sales
GROUP BY product_name
ORDER BY total DESC;
-- PostgreSQL crosstab (requires tablefunc extension)
SELECT * FROM crosstab(
'SELECT product, quarter, revenue FROM sales ORDER BY 1, 2',
'SELECT DISTINCT quarter FROM sales ORDER BY 1'
) AS ct(product TEXT, q1 NUMERIC, q2 NUMERIC, q3 NUMERIC, q4 NUMERIC);
```
### SQL Server PIVOT
```sql
-- SQL Server native PIVOT
SELECT *
FROM (
SELECT product_name, quarter, revenue
FROM quarterly_sales
) AS source
PIVOT (
SUM(revenue)
FOR quarter IN ([Q1], [Q2], [Q3], [Q4])
) AS pivoted;
```
---
## JSON Operations
### PostgreSQL JSONB
```sql
-- Query JSON fields
SELECT
id,
profile->>'name' AS name, -- text extraction
profile->'address'->>'city' AS city, -- nested extraction
(profile->>'age')::int AS age -- cast to int
FROM users
WHERE profile->>'country' = 'US'
AND (profile->>'age')::int >= 18;
-- JSONB containment
SELECT * FROM products
WHERE metadata @> '{"category": "electronics"}'; -- contains
-- JSONB existence
SELECT * FROM products
WHERE metadata ? 'warranty'; -- key exists
-- JSONB array queries
SELECT * FROM users
WHERE profile->'tags' ? 'premium'; -- array contains value
-- Update JSONB
UPDATE users
SET profile = jsonb_set(profile, '{address,city}', '"New York"')
WHERE id = 1;
-- JSONB aggregation
SELECT jsonb_agg(jsonb_build_object('id', id, 'name', name)) AS users_json
FROM users
WHERE is_active = true;
-- β HALLUCINATION TRAP: -> returns JSON, ->> returns TEXT
-- Filtering on -> requires JSON comparison
-- Filtering on ->> allows string comparison
-- Always cast ->> results when comparing numbers: (col->>'age')::int
```
---
## Indexing Strategy
### Index Types
```sql
-- B-tree (default β good for equality and range)
CREATE INDEX idx_users_email ON users (email);
-- Composite index (column order matters!)
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at DESC);
-- β Supports: WHERE user_id = 1 AND created_at > '2024-01-01'
-- β Supports: WHERE user_id = 1 (uses leftmost prefix)
-- β Does NOT support: WHERE created_at > '2024-01-01' (skips first column)
-- Partial / Filtered index (index only matching rows)
CREATE INDEX idx_active_users ON users (email) WHERE is_active = true;
-- Smaller index, faster queries when filtering by is_active
-- Covering index (INCLUDE β avoids table lookup)
CREATE INDEX idx_orders_covering ON orders (user_id)
INCLUDE (total, status, created_at);
-- All needed columns in the index = index-only scan
-- GIN index (for JSONB, arrays, full-text search)
CREATE INDEX idx_products_metadata ON products USING gin (metadata);
-- GiST index (for geometric, range, full-text)
CREATE INDEX idx_locations_geo ON locations USING gist (coordinates);
-- BRIN index (for naturally ordered data like timestamps)
CREATE INDEX idx_logs_timestamp ON logs USING brin (created_at);
-- Tiny index, perfect for append-only tables with timestamp ordering
```
### SARGability
```sql
-- SARGable = Search ARGument ABLE β can the query use an index?
-- β SARGable (index seekable)
WHERE created_at >= '2024-01-01'
WHERE email = 'alice@test.com'
WHERE name LIKE 'Ali%' -- prefix match
-- β NOT SARGable (forces full table scan)
WHERE YEAR(created_at) = 2024 -- function on column
WHERE LOWER(email) = 'alice@test.com' -- function on column
WHERE name LIKE '%alice%' -- leading wildcard
WHERE amount + tax > 100 -- expression on column
WHERE COALESCE(name, '') = '' -- function on column
-- β Fix: functional index (PostgreSQL)
CREATE INDEX idx_users_email_lower ON users (LOWER(email));
-- Now WHERE LOWER(email) = 'alice@test.com' IS SARGable
-- β Fix: computed column (SQL Server)
ALTER TABLE users ADD email_lower AS LOWER(email) PERSISTED;
CREATE INDEX idx_email_lower ON users (email_lower);
-- β HALLUCINATION TRAP: Implicit type conversions destroy SARGability
-- WHERE varchar_column = 123 β implicit cast on EVERY row
-- WHERE varchar_column = '123' β direct comparison, uses index
```
---
## EXPLAIN ANALYZE (Query Optimization)
```sql
-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM orders WHERE user_id = 42 AND status = 'completed';
-- Reading the output:
-- Seq Scan β full table scan (usually bad for large tables)
-- Index Scan β using an index to find rows (good)
-- Index Only Scan β all data from index, no table access (best)
-- Bitmap Scan β index + bitmap for multiple conditions (good for moderate selectivity)
-- Hash Join β building hash table for join (good for large joins)
-- Nested Loop β for each row in A, scan B (good for small datasets, bad for large)
-- Sort β explicit sorting (check if index can avoid this)
-- Key metrics:
-- actual time=X..Y β X = time to first row, Y = time to all rows (ms)
-- rows=N β actual rows returned
-- loops=N β number of times this node executed
-- Buffers: shared hit=N β pages read from cache (good)
-- Buffers: shared read=N β pages read from disk (measure of I/O cost)
-- SQL Server
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT * FROM orders WHERE user_id = 42;
-- Check: logical reads (from cache), physical reads (from disk)
-- β HALLUCINATION TRAP: EXPLAIN without ANALYZE shows estimates, NOT actuals
-- Always use EXPLAIN ANALYZE for real performance data
-- But CAREFUL: ANALYZE actually EXECUTES the query
-- For destructive queries (DELETE, UPDATE), wrap in a transaction:
BEGIN;
EXPLAIN ANALYZE DELETE FROM users WHERE id = 1;
ROLLBACK; -- prevents actual deletion
```
---
## Table Partitioning
```sql
-- PostgreSQL range partitioning (ideal for time-series data)
CREATE TABLE events (
id BIGSERIAL,
event_type TEXT NOT NULL,
payload JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
) PARTITION BY RANGE (created_at);
-- Create monthly partitions
CREATE TABLE events_2024_01 PARTITION OF events
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE events_2024_02 PARTITION OF events
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
-- Queries automatically prune partitions:
-- SELECT * FROM events WHERE created_at >= '2024-02-01'
-- Only scans events_2024_02 and later β skips events_2024_01 entirely
-- List partitioning (for categorical data)
CREATE TABLE orders (
id SERIAL,
region TEXT NOT NULL,
total NUMERIC
) PARTITION BY LIST (region);
CREATE TABLE orders_us PARTITION OF orders FOR VALUES IN ('US');
CREATE TABLE orders_eu PARTITION OF orders FOR VALUES IN ('EU', 'UK');
CREATE TABLE orders_apac PARTITION OF orders FOR VALUES IN ('JP', 'KR', 'AU');
```
---
## Transactions & Concurrency
```sql
-- Proper transaction pattern
BEGIN;
-- Lock the row for update (prevents concurrent modification)
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- Verify consistency
DO $$
BEGIN
IF (SELECT SUM(balance) FROM accounts) <> 10000 THEN
RAISE EXCEPTION 'Balance integrity violation';
END IF;
END $$;
COMMIT;
-- Isolation levels (ordered by strictness)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- default (PostgreSQL)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- snapshot isolation
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- strictest (may abort)
-- Advisory locks (application-level locking)
SELECT pg_advisory_lock(12345); -- acquire
-- ... do work ...
SELECT pg_advisory_unlock(12345); -- release
```
---
## MERGE / UPSERT
```sql
-- PostgreSQL UPSERT (ON CONFLICT)
INSERT INTO products (sku, name, price, updated_at)
VALUES ('ABC-123', 'Widget', 29.99, NOW())
ON CONFLICT (sku) DO UPDATE SET
name = EXCLUDED.name,
price = EXCLUDED.price,
updated_at = EXCLUDED.updated_at;
-- SQL Server MERGE
MERGE INTO products AS target
USING staging_products AS source
ON target.sku = source.sku
WHEN MATCHED THEN
UPDATE SET
name = source.name,
price = source.price,
updated_at = GETDATE()
WHEN NOT MATCHED THEN
INSERT (sku, name, price, created_at)
VALUES (source.sku, source.name, source.price, GETDATE());
-- β HALLUCINATION TRAP: PostgreSQL uses ON CONFLICT, not MERGE
-- MERGE was added in PostgreSQL 15+ but ON CONFLICT is idiomatic
-- SQL Server uses MERGE β do not confuse the two syntaxes
```
---
## Full-Text Search (PostgreSQL)
```sql
-- Create tsvector column and GIN index
ALTER TABLE articles ADD COLUMN search_vector tsvector;
UPDATE articles SET search_vector =
setweight(to_tsvector('english', COALESCE(title, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(body, '')), 'B');
CREATE INDEX idx_articles_search ON articles USING gin (search_vector);
-- Search with ranking
SELECT
title,
ts_rank(search_vector, query) AS rank
FROM articles, to_tsquery('english', 'database & optimization') AS query
WHERE search_vector @@ query
ORDER BY rank DESC
LIMIT 20;
-- Trigger to auto-update search vector
CREATE FUNCTION update_search_vector() RETURNS trigger AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('english', COALESCE(NEW.title, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(NEW.body, '')), 'B');
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER trg_articles_search
BEFORE INSERT OR UPDATE OF title, body ON articles
FOR EACH ROW EXECUTE FUNCTION update_search_vector();
```
---
## Security
```sql
-- β ALWAYS use parameterized queries
-- PostgreSQL (via psycopg)
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
-- Python SQLAlchemy
stmt = select(User).where(User.email == email)
-- β NEVER: String interpolation for SQL
-- β f"SELECT * FROM users WHERE email = '{email}'"
-- β "SELECT * FROM users WHERE email = '" + email + "'"
-- These allow SQL injection: email = "'; DROP TABLE users; --"
-- Row-Level Security (PostgreSQL)
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY documents_owner_policy ON documents
USING (owner_id = current_setting('app.current_user_id')::int);
-- Grant minimum permissions
GRANT SELECT, INSERT ON users TO app_role;
-- β NEVER: GRANT ALL ON DATABASE TO app_role
```
---
## Output Format
When this skill produces or reviews code, structure your output as follows:
```
βββ SQL Pro Report ββββββββββββββββββββββββ
Skill: SQL Pro
Database: [PostgreSQL/MySQL/SQL Server/Oracle]
Scope: [N queries Β· N tables]
βββββββββββββββββββββββββββββββββββββββββββββββββ
β Passed: [checks that passed, or "All clean"]
β οΈ Warnings: [non-blocking issues, or "None"]
β Blocked: [blocking issues requiring fix, or "None"]
βββββββββββββββββββββββββββββββββββββββββββββββββ
VBC status: PENDING β VERIFIED
Evidence: [EXPLAIN ANALYZE output / migration success / test pass]
```
**VBC (Verification-Before-Completion) is mandatory.**
Do not mark status as VERIFIED until concrete terminal evidence is provided.
## π¨ Edge-Case & Failure Mode Matrix
| Scenario | Risk | Production Mitigation |
|:---|:---|:---|
| **Empty or Null Inputs** | Unhandled exception or unexpected rendering collapse | Enforce fallback guards, optional chaining, and explicit empty state handlers |
| **Network Timeout / Latency** | Hanging operations or duplicate side-effects | Implement bounded abort controllers, exponential backoff, and idempotency keys |
| **Concurrency / Race Conditions** | Stale state overwrite or inconsistent data mutations | Use atomic transactions, mutex locking, or cancel-on-resubmit controls |
| **Invalid Schema / Malformed Payload** | Downstream runtime errors or security injection | Validate boundary payloads with Zod/Pydantic schemas prior to execution |
| **Resource / Memory Saturation** | OOM errors, frame drops, or memory leaks | Clean up listeners, cancel active timers, and enforce pagination/virtualization |
## ποΈ Tribunal Verification & Guardrails
**Active Reviewers:** `database-architect` Β· `sql-pro` Β· `security-auditor` Β· `schema-validator`
**Slash Command:** `/review` or `/tribunal-full`
### π¬ Evidence Standard (Tri-State Verification)
Every finding, audit statement, or completion claim must classify its factual certainty:
- **`[OBSERVED]`**: Directly confirmed in the codebase or verified via executed terminal command.
- **`[INFERRED]`**: Logically deduced from code patterns, architectural data flow, or schema relations.
- **`[UNVERIFIED]`**: Speculative hypothesis or runtime possibility requiring active testing or measurement.
### β Pre-Flight Self-Audit Checklist
```
β Are all queries parameterized against SQL injection vulnerabilities?
β Are composite indexes ordered by Equality, Sort, then Range (ESR)?
β Are multi-table writes wrapped in atomic transactions with rollback handlers?
β Are schema migrations backwards-compatible (expand-and-contract pattern)?
β Did I verify table and column names against active schema definitions?
```
### π Verification-Before-Completion (VBC) Protocol
**CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
- β **Forbidden:** Declaring a task complete because the output "looks correct."
- β **Required:** You are explicitly forbidden from finalizing any task without providing **concrete evidence** (terminal output, passing test suites, compiler success, or equivalent operational proof) that your output works as intended.