How to run and score evaluations for the neon-postgres-egress-optimizer skill.
Skill versions live in skill-versions/ as numbered files: SKILL-v001.md, SKILL-v002.md, etc. Each eval run uses a specific version and records it in results.csv.
Workflow:
- Copy the current version or create a new one in
skill-versions/ - Run evals against it
- Record results with the version number
- Iterate — create a new version for each change
- When a version consistently beats baseline, promote it:
# From the repo root:
cp evals/neon-postgres-egress-optimizer/skill-versions/SKILL-vXXX.md skills/neon-postgres-egress-optimizer/SKILL.md| ID | Type | Prompt |
|---|---|---|
| A | Vague | My Neon bill spiked to $400 this month, most of it is data transfer. Help me figure out why. |
| B | Moderate | Optimize the database egress in this project. |
Prompt C (specific, with pg_stat_statements data) is planned but deferred until the mock stats workflow is finalized. See eval-rubric.md for problem P3 details — it is only detectable via stats, so prompts A and B are expected to score 0 on P3 detection.
Baseline established from 89 runs without the skill on Opus 4.6 high effort.
| Problem | Without skill | Notes |
|---|---|---|
| P1: SELECT * unused columns | 89/89 detected, 89/89 fixed | Always caught. The skill won't improve this. |
| P2: Missing pagination | 0/89 detected, 0/89 fixed | Never caught. This is the primary target for the skill. |
| P3: High-frequency query | 0/89 detected, 0/89 fixed | Never caught. Expected — only detectable via pg_stat_statements data. |
| P4: Application-side aggregation | 87/89 detected, 87/89 fixed | Almost always caught. Rare misses come from omitting the aggregation issue entirely. |
| P5: Join duplication | 25/89 detected, 25/89 fixed | ~28% catch rate. When missed, the agent applies P1-style column narrowing instead of fixing the structural join. |
Tests passed on 89/89 baseline runs. Full results in results.csv.
| Problem | baseline (89 runs) | v003 (42 runs) |
|---|---|---|
| P1: SELECT * unused columns | 100% | 100% |
| P2: Missing pagination | 0% | 57% |
| P3: High-frequency query | 0% | 12% |
| P4: Application-side aggregation | 98% | 100% |
| P5: Join duplication | 28% | 100% |
P3 is expected to miss on prompts A/B — it requires pg_stat_statements data. Tests passed on all 139 runs. v001/v002 data (4 runs each) omitted due to small sample size; full history in results.csv.
./eval-run.ts --prompt A --skill 003 # skill run with v003
./eval-run.ts --prompt B # baseline run (no --skill)The script handles the full lifecycle:
- Copies the fixture to a temp workspace (
/tmp/eval-...) - Installs the skill version (if
--skillprovided) - Initializes git and launches Claude Code
- Captures a run-local diff artifact in the run log directory
- Runs
bun test(with retry + short delay on failure) - Captures a canonical diff to
diffs/(race-safe for parallel runs) - Launches Claude Code to score against
eval-rubric.md
Each run also writes phase logs and metadata to a log directory:
run-<id>.claude.logrun-<id>.tests.logrun-<id>.score.logrun-<id>.diffrun-<id>.summary.json
You can set this explicitly with --log-dir and --run-id (used by eval-batch.ts automatically).
Verify Claude Code outputs "Skill(neon-postgres-egress-optimizer) — Successfully loaded skill" at the start of the run. If it doesn't, the skill didn't trigger and the run is effectively a baseline. Note this in the results.csv notes column.
To force the skill, abort and re-run with: claude "/neon-postgres-egress-optimizer <prompt>"
Open eval-rubric.md and answer each yes/no question per problem against the diff. Record one row in results.csv.
Columns:
date— YYYY-MM-DDfixture— fixture name (e.g.,hono-drizzle-app)prompt— which prompt was used (A, B)model— Claude model version usedskill_version— version fromskill-versions/(e.g.,v001); empty for baseline runsdiff_file— filename of the saved diff in diffs/ (e.g.,01_20260311_A_baseline.diff)p1_detectedthroughp5_detected— yes/nop1_fixedthroughp5_fixed— yes/notests_pass— yes/no (runbun testafter the agent's changes)notes— free text for anything notable
Generate the baseline and results summary tables from results.csv:
./eval-stats.tsCopy the output into the baseline and results summary sections above.
For v1, score manually against the rubric. To use Claude Code as judge:
- Copy fixture to temp directory
- Run Claude Code with skill installed + one prompt → produces a git diff
- Feed diff + original fixture code +
eval-rubric.mdto a second Claude Code instance - Judge outputs detected/fixed per problem + test pass status
- Append row to
results.csv
First few runs: verify the judge's scoring manually. Once trustworthy, human spot-checks only.