agentsclimarketplace

Enum value discovery before sql where

Skill Ed3Design/ed3design-skill-bundles/schema-discipline/skills/enum-value-discovery-before-sql-where

Claude Code skill bundles for software engineering: 56 skills + 5 Python tools + 6 hooks + 4 sub-agents across 6 thematic plugins (token-savers, code-quality, planning-disciplines, async-forensik, schema-discipline, skill-system-meta). Empirically TDD-validated patterns, MIT licensed.

Install
npx -y skills add Ed3Design/ed3design-skill-bundles --skill enum-value-discovery-before-sql-where

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use BEFORE writing any SQL WHERE-clause that filters on a string/enum-typed column. Schema-verify via `\d <table>` shows COLUMN TYPE (text/varchar/enum) but NOT the actual values used. Code may set 'taken' while the reviewer thinks 'accept'. Pattern: run `SELECT DISTINCT <col> FROM <table>` (or grep for `_update_<col>`-style setters) to discover the actual value-set BEFORE formulating WHERE. Without this discovery step, queries silently return wrong counts: rows matching the real value get excluded, user sees "0 results" while reality has many. Trigger on phrases like "how many entities with status X exist", "user_response='accept'", "SELECT ... WHERE enum_col=...", "why am I seeing no hits", "forensic DB analysis", "cockpit filter shows 0". Do NOT load for known well-defined PostgreSQL ENUM types where `\d` shows values inline, first-time-CREATE-TABLE queries, or non-text/non-enum columns.

SKILL.md

9.1 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it

enum-value-discovery-before-sql-where

PROMOTED: Pattern emerged from a production domain forensic session. TDD pressure test passed: GREEN subagent recognized the example as a 1:1 scenario and avoided the WHERE user_response='accept' anti-pattern; RED produced the same anti-pattern (was self-critical, but would have delivered a wrong query to the user).

Pattern (short form)

Before any SQL WHERE clause with a string-/enum-typed column:

  1. Schema check (maxim "verify DB schema"): \d <table> → returns COLUMN + TYPE, BUT not the actual values in use
  2. Value discovery: SELECT DISTINCT <col> FROM <table> ORDER BY 1; → returns the real values. OR alternatively: code grep for setters (_update_<col>, SET <col> = '...').
  3. Only then formulate the WHERE clause with verified values

If (3) is done without (2) → query silently returns wrong counts. Reviewer sees "0 rows" where reality has many, falls into a wrong conclusion spiral.

Concrete example (live encounter)

Task: Forensic baseline for your-app's signal performance.

Wrong query:

SELECT
  date_trunc('week', triggered_at)::date AS week_start,
  SUM(CASE WHEN user_response='accept' THEN 1 ELSE 0 END) AS user_accepted
FROM v3_signals
WHERE triggered_at >= NOW() - INTERVAL '4 weeks'
GROUP BY 1;

Result: user_accepted = 0 in ALL weeks. Conclusion: "User-Response-Loop is broken, the user has never accepted".

User correction: "I have indeed accepted signals (Alphabet, Bayer)."

Reality via value discovery:

SELECT user_response, COUNT(*) FROM v3_signals GROUP BY user_response;
 user_response | count
---------------+-------
 pending       |   107
 taken         |    17  ← the user's accepts here!
 skipped       |     5

→ Code sets 'taken', not 'accept'. Grep verification in code:

grep -rn "user_response\s*=" --include="*.py" .
# strategic/v3_trade_manager.py:96: mark_signal_taken → 'taken'
# strategic/v3_trade_manager.py:100: mark_signal_skipped → 'skipped'

→ Original query must be corrected to WHERE user_response='taken'. Reality was 17 accepts, not 0.

Quick reference: when to discover, when to skip

SituationDiscovery needed?
WHERE on text/varchar column with string value✅ YES, always
WHERE on PostgreSQL ENUM type (CREATE TYPE ... AS ENUM)⚠️ No if \d shows the values — else YES
WHERE on boolean❌ No (only 2 values)
WHERE on integer with range filter (>, <)❌ No
WHERE on timestamp/date❌ No
WHERE on id IN (...) with concrete IDs❌ No
JOIN condition with string column✅ YES for both tables
AGGREGATE like SUM(CASE WHEN col='X' THEN ...)✅ YES — same trap as WHERE

Discovery methods (in order of speed)

A. DB query (1-2s, always correct)

SELECT DISTINCT <col> FROM <table> ORDER BY 1;
-- or with counts:
SELECT <col>, COUNT(*) FROM <table> GROUP BY <col> ORDER BY 2 DESC LIMIT 20;

B. Code grep (5-10s, shows setter intent)

# Where is the column set?
grep -rn "SET <col>\s*=" --include="*.py" --include="*.sql"
grep -rn "<col>\s*=\s*['\"]" --include="*.py"
# Functions that set the value:
grep -rn "mark_<entity>\|set_<col>\|update_<col>" --include="*.py"

C. Schema-migration backtrace (complex, only for history questions)

grep -rn "<col>" core/db/migrations.py  # if initialized there
git log -p -- core/db/migrations.py | grep -A 2 "<col>"

→ For live forensics: A first. For code-understanding questions without live DB: B first.

Anti-Patterns

Anti-PatternCorrect
WHERE status='active' without discoveryfirst SELECT DISTINCT status FROM ...
"Status values are always pending/accept/reject" — assumption from training dataevery system has its own convention, verify
Forensic report presenting "0 rows match" as findingfirst value discovery, otherwise wrong conclusion
\d <table> as sufficient schema verificationSchema only tells TYPE, not VALUES
Skipping discovery on AGGREGATE functions (SUM(CASE WHEN col='X'...))same trap as WHERE — aggregates with wrong string silently return 0
Ignoring the user's "it works" against data resultif user reality ≠ data, the query is suspect — run discovery

Discovery surrogates without live DB access

If you have no live psql (subagent context, code review without prod access, new codebase without DB setup):

  1. Code grep for setters is the primary surrogate:
    grep -rn "mark_<entity>\|set_<col>\|<col>\s*=\s*['\"]" --include="*.py"
    
  2. Read migration file if available: often initial values or CHECK constraints are defined there
  3. Test fixtures in tests/ often show the canonical values (by convention factories/<table>.py)
  4. Fall back to the caller (instead of guessing): "I need SELECT DISTINCT <col> FROM <table> output before I can finalize the WHERE clause. Can you run that or is the output available?" — frame it explicitly as a precondition, do not heuristically guess and hope.

→ This option is more legitimate than the training-data heuristic ('accept'/'accepted') because it explicitly hands the uncertainty back to the caller's setup rather than silently burying it in the query.

Background: TDD progress (Bulletproofing Log)

Cycle 1 — PASS via Subagent-Pair-Dispatch

  • RED subagent (without skill, prompt: "Write SQL for 4-week accepts on v3_signals.user_response"): wrote WHERE user_response = 'accepted' from training-data heuristic. Was self-critical in step 3 ("guessed heuristically, I did NOT check which distinct values are actually in the column") — recognized the gap but did not act on it. Would have given the user a wrong count=0 query.

  • GREEN subagent (with skill, identical prompt): prepended a discovery query as Step 0 → SELECT user_response, COUNT(*) FROM v3_signals GROUP BY user_response. Recognized the example in the skill as a 1:1 match → adopted 'taken' as verified code value. Additionally documented "if count=0 do not draw naive conclusion" as anti-pattern.

  • Refactor applied: Section "Discovery surrogates without live DB access" added (from GREEN self-reflection: "hint for what to do when a subagent has NO live DB access — the skill implicitly assumes executable psql"). Closes caller-context bias for subagents without DB tool.

Cycle-2 Backlog (Polish, non-blocking)

  1. REST API variant: pattern applies analogously to REST query params with enum-typed filter — separate section "Enum discovery for API filters (not just SQL)"
  2. GraphQL variant: schema introspection vs resolver actual values — presumably same bug class, worth its own section
  3. Cross-skill synergy with pre-migration-data-verification: in migration cleanup, discovery is MANDATORY also for the WHERE of UPDATE/DELETE statements — perhaps reinforce cross-reference

Cross-references

  • maxim "verify DB schema before every query" — column verification
  • This skill is the separate value-verification layer to column verification
  • pre-migration-data-verification — related: count data violations before constraint add
  • maxim "counter-thesis check" — "could the 0 be wrong?" is a counter-thesis that leads to discovery

Real-world impact

Forensic baseline for production domain:

  • Initial query: 0 user_accepts in 4 weeks → conclusion "user-response loop broken"
  • User correction: "Indeed I have, Alphabet + Bayer"
  • Value discovery showed: 17 'taken', 0 'accept' (code value is 'taken')
  • Result: bug was in MY query, not in the system. Would have led to wrong forensic conclusion ("user-response pipeline broken") — and correspondingly wrong code-repair sessions.

Time savings when correctly applied: ~30-60 min of misdiagnosis detour avoided.

Notes for skill reviewer (next session)

  • If skill fails TDD: possibly just the maxim "DB schema before every query" — adding a "values before every WHERE" clause is enough.
  • If TDD passes strongly: could become cross-project standard (all SQL forensic sessions)
  • Variant to evaluate: does it also apply to API filters (REST query params with enum)?

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most databases sql skills give in ~2.1k tokens

Counted across 589 of the 662 authors here whose files we hold, read 2026-08-07

  • Use parameterized queriesin 37 of 589, across 34 files
  • Use timestamptz for timestampsin 30 of 589, across 14 files
  • Index foreign keysin 29 of 589, across 18 files
  • Create indexes concurrentlyin 29 of 589, across 24 files
  • Use numeric type for moneyin 25 of 589, across 8 files
  • Use cursor pagination instead of offsetin 24 of 589, across 17 files
  • Select only required columnsin 24 of 589, across 20 files
  • Add indexes manually on foreign key columnsin 22 of 589, across 12 files
  • Normalize to third normal formin 19 of 589, across 10 files
  • Configure connection poolingin 19 of 589, across 17 files
  • Put equality columns before range columns in indexesin 18 of 589, across 10 files
  • Read individual rule files for detailed explanationsin 18 of 589, across 4 files

Said here and by no other author read

  • discover actual string values before filtering
  • run SELECT DISTINCT to find values
  • grep codebase for column setter functions
  • verify values before formulating the WHERE clause
  • apply discovery to aggregate functions using string columns
  • request distinct values from caller without live database

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 327,069. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.