@brunosps00/dev-workflow 0.13.0 → 0.15.0

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.
Files changed (46) hide show
  1. package/README.md +9 -3
  2. package/package.json +1 -1
  3. package/scaffold/en/commands/dw-bugfix.md +2 -1
  4. package/scaffold/en/commands/dw-code-review.md +1 -0
  5. package/scaffold/en/commands/dw-create-tasks.md +6 -0
  6. package/scaffold/en/commands/dw-deps-audit.md +1 -1
  7. package/scaffold/en/commands/dw-fix-qa.md +1 -1
  8. package/scaffold/en/commands/dw-functional-doc.md +1 -1
  9. package/scaffold/en/commands/dw-help.md +1 -1
  10. package/scaffold/en/commands/dw-redesign-ui.md +1 -1
  11. package/scaffold/en/commands/dw-run-qa.md +2 -1
  12. package/scaffold/en/commands/dw-run-task.md +1 -1
  13. package/scaffold/pt-br/commands/dw-bugfix.md +2 -1
  14. package/scaffold/pt-br/commands/dw-code-review.md +1 -0
  15. package/scaffold/pt-br/commands/dw-create-tasks.md +6 -0
  16. package/scaffold/pt-br/commands/dw-deps-audit.md +1 -1
  17. package/scaffold/pt-br/commands/dw-fix-qa.md +1 -1
  18. package/scaffold/pt-br/commands/dw-functional-doc.md +1 -1
  19. package/scaffold/pt-br/commands/dw-help.md +1 -1
  20. package/scaffold/pt-br/commands/dw-redesign-ui.md +1 -1
  21. package/scaffold/pt-br/commands/dw-run-qa.md +2 -1
  22. package/scaffold/pt-br/commands/dw-run-task.md +1 -1
  23. package/scaffold/skills/dw-incident-response/SKILL.md +164 -0
  24. package/scaffold/skills/dw-incident-response/references/blameless-discipline.md +126 -0
  25. package/scaffold/skills/dw-incident-response/references/communication-templates.md +107 -0
  26. package/scaffold/skills/dw-incident-response/references/postmortem-template.md +133 -0
  27. package/scaffold/skills/dw-incident-response/references/runbook-templates.md +169 -0
  28. package/scaffold/skills/dw-incident-response/references/severity-and-triage.md +186 -0
  29. package/scaffold/skills/dw-llm-eval/SKILL.md +148 -0
  30. package/scaffold/skills/dw-llm-eval/references/agent-eval.md +252 -0
  31. package/scaffold/skills/dw-llm-eval/references/judge-calibration.md +169 -0
  32. package/scaffold/skills/dw-llm-eval/references/oracle-ladder.md +171 -0
  33. package/scaffold/skills/dw-llm-eval/references/rag-metrics.md +186 -0
  34. package/scaffold/skills/dw-llm-eval/references/reference-dataset.md +190 -0
  35. package/scaffold/skills/dw-testing-discipline/SKILL.md +99 -76
  36. package/scaffold/skills/dw-testing-discipline/references/agent-guardrails.md +170 -0
  37. package/scaffold/skills/dw-testing-discipline/references/anti-patterns.md +6 -6
  38. package/scaffold/skills/dw-testing-discipline/references/core-rules.md +128 -0
  39. package/scaffold/skills/dw-testing-discipline/references/playwright-recipes.md +2 -2
  40. package/scaffold/skills/dw-ui-discipline/SKILL.md +101 -79
  41. package/scaffold/skills/dw-ui-discipline/references/hard-gate.md +93 -73
  42. package/scaffold/skills/dw-ui-discipline/references/visual-slop.md +152 -0
  43. package/scaffold/skills/dw-testing-discipline/references/ai-agent-gates.md +0 -170
  44. package/scaffold/skills/dw-testing-discipline/references/iron-laws.md +0 -128
  45. package/scaffold/skills/dw-ui-discipline/references/anti-slop.md +0 -162
  46. /package/scaffold/skills/dw-testing-discipline/references/{positive-patterns.md → patterns.md} +0 -0
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: dw-llm-eval
3
+ description: Use when authoring or reviewing AI/LLM features (chat, RAG, summarization, classifiers, agents) — enforces an oracle ladder (climb from exact match up to LLM-as-judge), reference-dataset discipline, judge calibration (Spearman ≥0.80), and trajectory-vs-outcome agent eval so AI features ship with measurable behavior instead of "looks good to me" QA.
4
+ ---
5
+
6
+ # LLM Evaluation
7
+
8
+ > Adapted patterns from [`langchain-ai/agentevals`](https://github.com/langchain-ai/agentevals) (MIT) for trajectory-match modes, plus general LLM-eval discipline from OpenAI evals cookbook, Anthropic's evals guidance, and the broader open evaluations literature. Material rewritten in our voice.
9
+
10
+ ## When this skill applies
11
+
12
+ - Any feature that uses an LLM in production: chat, summarization, classification, RAG (retrieval-augmented generation), agents, tool-use, structured extraction, code generation.
13
+ - `/dw-create-tasks` when the PRD mentions an AI feature — eval planning becomes a mandatory subtask.
14
+ - `/dw-code-review` when the diff touches AI feature code paths.
15
+ - `/dw-run-qa --ai` when validating an AI feature against its reference dataset.
16
+
17
+ If the feature is fully deterministic (no LLM in the loop), use `dw-testing-discipline` instead — Iron rules and 25 anti-patterns. This skill is specifically for entropy-tolerant systems.
18
+
19
+ ## First principle
20
+
21
+ > Tests for deterministic code assert exact outputs.
22
+ > Tests for LLM features assert behaviors within tolerance.
23
+ > The discipline is choosing the right tolerance — and proving it's not "anything passes."
24
+
25
+ ## The oracle ladder
26
+
27
+ Five rungs, climb from CHEAPEST/STRICTEST to MOST EXPENSIVE/SUBJECTIVE. Always start at the bottom; only climb when the lower rung can't cover the case.
28
+
29
+ | Rung | What it checks | Cost | When to use |
30
+ |------|----------------|------|-------------|
31
+ | 1. **Exact match** | `output === expected` | ~free | Structured outputs (function calls, JSON with stable shape, classifications) |
32
+ | 2. **Schema validation** | Output matches JSON schema / type contract | ~free | Output shape matters; specific values vary |
33
+ | 3. **Outcome state** | Side effect produced the expected change (DB row, file written, tool called) | cheap | Agents, tool-use, RAG with concrete answers |
34
+ | 4. **LLM-as-judge** | A different model grades the output against a rubric | medium ($$$) | Subjective quality (helpfulness, tone, faithfulness) where no rule can decide |
35
+ | 5. **Human review** | Domain expert scores | expensive | Calibration of rung 4; high-stakes outputs; edge cases |
36
+
37
+ **Rule:** never reach for rung 4 before checking if rungs 1-3 can cover the case. Every rung up costs an order of magnitude more (latency, money, calibration effort) — and adds entropy.
38
+
39
+ See `references/oracle-ladder.md` for examples per rung and the climbing decision tree.
40
+
41
+ ## LLM-as-judge discipline (when rung 4 is needed)
42
+
43
+ Without calibration, LLM-as-judge produces noise dressed as signal. Three non-negotiables:
44
+
45
+ 1. **Calibrate against humans** — ≥20 human-graded cases, compute Spearman correlation against LLM-as-judge. Target ≥0.80. Below that, reject the judge configuration.
46
+ 2. **Use a different model than the system under test** — same model judging itself produces false positives. Pair: GPT-4 generates → Claude judges. Or vice versa.
47
+ 3. **Rubric, not free-form** — provide the judge a structured rubric (criteria + scale + examples) instead of "rate quality 1-10."
48
+
49
+ See `references/judge-calibration.md` for the full calibration recipe, rubric templates, and the "judge drift" monitoring pattern.
50
+
51
+ ## Reference dataset principle
52
+
53
+ > 20 unambiguous cases drawn from real production failures beat 200 synthetic perfect cases.
54
+
55
+ The dataset is the bedrock. Without a reference set, every "improvement" is anecdote.
56
+
57
+ Structure:
58
+ ```
59
+ .dw/eval/datasets/<feature-name>/
60
+ ├── cases.jsonl # input + expected (or rubric reference) per line
61
+ ├── README.md # provenance, sample size, when last reviewed
62
+ └── runs/<YYYY-MM-DD>.jsonl # results of each eval run
63
+ ```
64
+
65
+ See `references/reference-dataset.md` for case-design principles, sampling from production, and when to expand the set.
66
+
67
+ ## RAG evaluation
68
+
69
+ Three orthogonal metrics — measure all three, not just one:
70
+
71
+ | Metric | What it measures | Tool |
72
+ |--------|-----------------|------|
73
+ | **Retrieval precision@k** | Of the top-K retrieved chunks, how many were relevant | Exact match against labeled ground-truth |
74
+ | **Answer faithfulness** | Does the answer cite only what the retrieved context supports? | LLM-as-judge with rubric |
75
+ | **Context utilization** | Did the answer USE the retrieved context, or hallucinate around it? | Heuristic + LLM-as-judge |
76
+
77
+ Precision alone misses hallucination. Faithfulness alone misses retrieval failure. Context utilization alone misses both. See `references/rag-metrics.md` for the full implementation.
78
+
79
+ ## Agent / tool-use evaluation
80
+
81
+ Two questions distinguish good agent eval from bad:
82
+
83
+ ### Question 1: outcome or trajectory?
84
+
85
+ | Approach | What it checks | Failure mode |
86
+ |----------|---------------|--------------|
87
+ | **Outcome-only** | Did the agent achieve the goal? Was the final state correct? | Misses "ghost actions" — agent did the right thing for the wrong reasons |
88
+ | **Trajectory** | Did the agent take the expected sequence of steps / tool calls? | Punishes legitimate creativity — agent solved it via a different valid path |
89
+
90
+ **Recommendation:** outcome-only with side-effect assertion as default. Trajectory match for cases where the path matters (e.g., "must call `get-user` before `update-user`").
91
+
92
+ ### Question 2: which trajectory match mode?
93
+
94
+ When trajectory matching IS the right call, four modes are available:
95
+
96
+ - **Strict** — same tool calls, same order, same arguments. Use when both sequence and parameters are part of the contract.
97
+ - **Unordered** — same tool calls, any order. Use when concurrent calls are valid.
98
+ - **Subset** — actual trajectory contains a subset of reference calls. Use to enforce "don't exceed expected tool use" (frugality / cost).
99
+ - **Superset** — actual contains all reference calls plus possibly more. Use when specific tools are mandatory but extras are acceptable.
100
+
101
+ See `references/agent-eval.md` for examples and the decision tree.
102
+
103
+ ## Required reading by context
104
+
105
+ | Doing what | Read |
106
+ |------------|------|
107
+ | Designing an eval suite for an AI feature | `references/oracle-ladder.md` (climb the ladder) |
108
+ | Using LLM-as-judge | `references/judge-calibration.md` (mandatory before relying on it) |
109
+ | Building / curating a reference dataset | `references/reference-dataset.md` |
110
+ | RAG-specific feature | `references/rag-metrics.md` |
111
+ | Agent / tool-use feature | `references/agent-eval.md` |
112
+
113
+ ## Anti-patterns (will block in `/dw-code-review`)
114
+
115
+ - **LLM-as-judge without calibration evidence.** PR adds LLM-as-judge but the calibration Spearman score is missing or < 0.80. REJECTED.
116
+ - **Same-model judge.** Judge model is the same as the system under test. REJECTED unless explicitly documented (and even then, results are suspect).
117
+ - **Single-rung eval.** Feature ships with only LLM-as-judge; no rung 1-3 grounding. REJECTED — the cheap rungs catch the loud failures.
118
+ - **Synthetic-only dataset.** No traceable production-failure source for any case. REJECTED — confirm at least 20% of cases come from real user inputs.
119
+ - **"Looks good to me" QA.** No reference dataset, no metric, no rubric — just sampling output and calling it good. REJECTED.
120
+ - **Coverage as metric.** Quoting "we tested 50 prompts" without saying what was measured. The number is meaningless without the metric.
121
+
122
+ ## Integration with dev-workflow commands
123
+
124
+ - `/dw-create-tasks`: when the PRD has an AI feature requirement, an eval-plan subtask is mandatory. The task references this skill's oracle ladder.
125
+ - `/dw-code-review`: AI feature PRs require a reference dataset + ≥2 oracle rungs (lower rungs FIRST). The constitution gate also applies — if the project has principles about AI feature reliability, they're enforced here.
126
+ - `/dw-run-qa --ai`: new mode (when this skill is bundled) — runs the reference dataset against the current implementation, logs to `QA/logs/ai/<feature>-<date>.jsonl`, computes precision@k / faithfulness / outcome accuracy per the feature type.
127
+ - `/dw-bugfix` when the bug is an AI failure mode (hallucination, tool misuse, classification error): adds the failing case to the reference dataset BEFORE fixing — the case is now a regression test forever.
128
+
129
+ ## When the discipline bends
130
+
131
+ - **Prototype / spike phase**: skip calibration; document as "spike — eval added before merge to main."
132
+ - **Internal-only AI feature with low blast radius** (e.g., classifier for internal CRM tags): rung 1-3 only is fine; LLM-as-judge may be overkill.
133
+ - **Real-time features where eval can't run synchronously**: shadow-eval pattern — run the eval async on a sample of production traffic; alert on regression.
134
+
135
+ In all bend cases, document the deviation in the techspec / PR. "Skipped judge calibration because internal-only feature affecting <100 users" is fine; just say it.
136
+
137
+ ## Why this approach
138
+
139
+ Two failure modes drive most AI feature regressions:
140
+
141
+ 1. **No measurement** — team ships, suspects it's worse, can't prove it, debate.
142
+ 2. **Wrong measurement** — team measures LLM-as-judge only, judge drifts with the model, scores rise while real quality falls.
143
+
144
+ The oracle ladder fixes both: forces measurement, forces ANCHORED measurement (lower rungs are deterministic; upper rungs are calibrated against them).
145
+
146
+ ## Bottom line
147
+
148
+ > An AI feature without an eval suite is a feature you can't ship safely. An eval suite without calibration is a number you can't trust. Build the dataset from real failures, climb the ladder from cheap to expensive, calibrate the judge against humans, and re-run before every model swap. The discipline is small; the absence of it is one of the largest sources of "we shipped and don't know if it's worse" experiences in the industry.
@@ -0,0 +1,252 @@
1
+ # Agent evaluation — outcome vs trajectory
2
+
3
+ Agent eval has a foundational question: do you grade **what the agent did along the way** (trajectory) or **what state the world is in at the end** (outcome)?
4
+
5
+ The answer determines what you measure and what failure modes you catch.
6
+
7
+ ## Outcome-only evaluation (recommended default)
8
+
9
+ **What it checks:** at the end of the agent's run, does the world look the way it should? Was the right tool called? Was the right ticket filed? Was the user's question answered correctly?
10
+
11
+ **Pattern:**
12
+
13
+ ```javascript
14
+ test('agent files refund ticket when user requests refund', async () => {
15
+ await agent.run('I want a refund for order #123');
16
+
17
+ // Outcome assertions
18
+ const tickets = await db.tickets.findMany({ where: { order_id: '123' } });
19
+ expect(tickets).toHaveLength(1);
20
+ expect(tickets[0].type).toBe('refund');
21
+
22
+ const userMessage = agent.lastMessage();
23
+ expect(userMessage).toMatch(/refund.*processed|filed|submitted/i);
24
+ });
25
+ ```
26
+
27
+ **Strengths:**
28
+ - Permits creative paths — agent solved it via tool A → B → C OR via tool A → C → B; both pass if the outcome is right.
29
+ - Robust to internal refactor — restructuring the agent's prompt or tool descriptions doesn't break the test as long as the outcome holds.
30
+ - Aligned with what users care about: did the system do the right thing?
31
+
32
+ **Weaknesses:**
33
+ - Misses "ghost actions" — agent claims to have done X but the outcome state shows it didn't.
34
+ - Defense: combine with rung-3 outcome-state assertions (DB writes, API calls). Don't trust the agent's word.
35
+ - Misses inefficiency — agent took 17 tool calls to do what should be 3. Outcome OK but cost is bad.
36
+ - Defense: track tool-call count as a separate metric; alert if it exceeds budget.
37
+
38
+ ## Trajectory evaluation (when path matters)
39
+
40
+ **What it checks:** did the agent take the expected sequence (or set) of tool calls? Match against a reference trajectory.
41
+
42
+ **Use when:**
43
+ - Compliance / audit requires specific actions in specific order (e.g., "ALWAYS verify identity before disclosing balance").
44
+ - Safety-critical: a specific tool MUST be called (e.g., "if user mentions self-harm, must invoke `escalate-to-human` BEFORE any other action").
45
+ - The path itself is the contract (e.g., a workflow agent that must traverse a specific decision tree).
46
+
47
+ ## Trajectory match modes
48
+
49
+ Four modes, from strictest to most permissive:
50
+
51
+ ### Strict
52
+
53
+ **Rule:** actual trajectory contains identical tool calls in identical order with identical arguments.
54
+
55
+ **Use when:** path AND parameters are both part of the contract. Compliance, deterministic workflow agents.
56
+
57
+ ```javascript
58
+ expect(actualToolCalls).toEqual([
59
+ { name: 'verify_identity', args: { user_id: 'u-42' } },
60
+ { name: 'get_balance', args: { account_id: 'a-99' } },
61
+ { name: 'respond_to_user', args: { template: 'balance-inquiry' } },
62
+ ]);
63
+ ```
64
+
65
+ ### Unordered
66
+
67
+ **Rule:** actual contains the same set of tool calls, any order; arguments match.
68
+
69
+ **Use when:** the agent legitimately may parallelize or reorder calls without affecting correctness.
70
+
71
+ ```javascript
72
+ expect(new Set(actualToolNames)).toEqual(new Set(['fetch_user', 'fetch_orders', 'fetch_addresses']));
73
+ ```
74
+
75
+ ### Subset
76
+
77
+ **Rule:** actual trajectory is a SUBSET of reference — agent didn't exceed expected tool calls.
78
+
79
+ **Use when:** frugality / cost discipline — "agent should NOT call expensive tools unnecessarily."
80
+
81
+ ```javascript
82
+ // Reference is the maximum allowed set
83
+ const referenceToolCalls = ['fetch_user', 'classify_intent', 'respond'];
84
+ const allActualInReference = actualToolNames.every(t => referenceToolCalls.includes(t));
85
+ expect(allActualInReference).toBe(true);
86
+ ```
87
+
88
+ ### Superset
89
+
90
+ **Rule:** actual contains ALL reference tool calls, possibly plus extras.
91
+
92
+ **Use when:** specific tools are mandatory but extras are acceptable. Often safety-critical ("MUST log audit event") while permitting agent autonomy in other tool choices.
93
+
94
+ ```javascript
95
+ // Reference is the minimum required set
96
+ const requiredToolCalls = ['log_audit_event', 'verify_user'];
97
+ const allRequiredCalled = requiredToolCalls.every(t => actualToolNames.includes(t));
98
+ expect(allRequiredCalled).toBe(true);
99
+ ```
100
+
101
+ ## Argument matching strategies
102
+
103
+ When trajectory matching, how should tool ARGUMENTS be compared?
104
+
105
+ | Strategy | Behavior | Use |
106
+ |----------|---------|-----|
107
+ | **Exact** | Arguments must match byte-for-byte | Deterministic args (IDs, fixed strings) |
108
+ | **Ignore** | Any call to the right tool counts | When the call ITSELF is what matters, not args |
109
+ | **Subset** | Actual args contain at least the reference args | Required fields enforced; extras OK |
110
+ | **Superset** | Actual args are within reference args set | Frugality — agent didn't add unexpected fields |
111
+ | **Custom comparator** | Per-tool comparison function | Domain-specific equivalence (case-insensitive, semantic match) |
112
+
113
+ Example with custom comparator:
114
+
115
+ ```javascript
116
+ const matchers = {
117
+ 'search_cities': (actualArgs, refArgs) => {
118
+ // City name comparison: case-insensitive, trimmed
119
+ return actualArgs.name.toLowerCase().trim() === refArgs.name.toLowerCase().trim();
120
+ },
121
+ 'fetch_user': 'exact',
122
+ };
123
+ ```
124
+
125
+ ## Decision tree: outcome vs trajectory
126
+
127
+ ```
128
+ Is correctness defined by the FINAL STATE or by the PATH?
129
+
130
+ ├── Final state only — agent can solve it however it likes
131
+ │ → Outcome-only eval. Combine with rung-3 state assertions.
132
+
133
+ ├── Specific tool calls MUST happen for compliance/safety
134
+ │ → Superset trajectory mode. Outcome too, as a separate check.
135
+
136
+ ├── Specific tool calls MUST NOT happen (cost / privacy)
137
+ │ → Subset trajectory mode.
138
+
139
+ ├── The full workflow path is the contract (legal, audit)
140
+ │ → Strict trajectory mode.
141
+
142
+ └── Path is partly fixed, partly free
143
+ → Trajectory with custom comparator OR split into multiple smaller tests.
144
+ ```
145
+
146
+ ## Cost vs accuracy tracking
147
+
148
+ Two metrics that trajectory eval naturally enables:
149
+
150
+ ### Tool-call efficiency
151
+
152
+ ```python
153
+ def efficiency_score(actual_trajectory, reference_trajectory):
154
+ actual_calls = len(actual_trajectory)
155
+ reference_calls = len(reference_trajectory)
156
+ if reference_calls == 0:
157
+ return 1.0
158
+ return min(1.0, reference_calls / actual_calls)
159
+ ```
160
+
161
+ Score 1.0 = matched or beat reference. Score 0.5 = took 2× the expected calls.
162
+
163
+ Track this over time; agent regressions sometimes show up as efficiency loss before outcome loss.
164
+
165
+ ### Step-count percentile
166
+
167
+ ```
168
+ Run 2026-05-12:
169
+ p50 tool calls: 4 (reference 3)
170
+ p95 tool calls: 9 (reference 6)
171
+ p99 tool calls: 18 (reference 12)
172
+ ```
173
+
174
+ p99 spikes catch cases where the agent enters a loop or backtracks excessively — outcome may still be correct but cost runaway is real.
175
+
176
+ ## Dataset structure for agents
177
+
178
+ ```json
179
+ {
180
+ "id": "agent-case-001",
181
+ "input": {
182
+ "user_message": "Cancel my order #123 and request a refund"
183
+ },
184
+ "expected_outcome": {
185
+ "tickets_created": [
186
+ { "type": "refund", "order_id": "123" }
187
+ ],
188
+ "order_status": "cancelled"
189
+ },
190
+ "expected_trajectory": {
191
+ "mode": "superset",
192
+ "required_calls": [
193
+ { "name": "verify_user_owns_order", "args_match": "exact" },
194
+ { "name": "update_order_status", "args_match": "subset", "args": { "status": "cancelled" } },
195
+ { "name": "create_refund_ticket", "args_match": "subset" }
196
+ ],
197
+ "forbidden_calls": ["delete_user_data"]
198
+ },
199
+ "tool_budget": { "p95_max_calls": 8 }
200
+ }
201
+ ```
202
+
203
+ The `forbidden_calls` field is powerful — explicitly enumerate tools that MUST NOT fire for this input class. Catches "agent escalated to a dangerous tool that wasn't necessary."
204
+
205
+ ## Combining outcome + trajectory
206
+
207
+ For serious agent eval, combine both:
208
+
209
+ ```javascript
210
+ test('agent handles refund request', async () => {
211
+ const result = await agent.run(case.input);
212
+
213
+ // Outcome
214
+ expectOutcomeMatch(result.outcome, case.expected_outcome);
215
+
216
+ // Trajectory — superset mode (required tools called)
217
+ expectTrajectoryMatch(result.trajectory, case.expected_trajectory, 'superset');
218
+
219
+ // Forbidden — none of these tools fired
220
+ for (const forbidden of case.expected_trajectory.forbidden_calls) {
221
+ expect(result.trajectory.some(t => t.name === forbidden)).toBe(false);
222
+ }
223
+
224
+ // Budget — didn't exceed expected tool calls
225
+ expect(result.trajectory.length).toBeLessThanOrEqual(case.tool_budget.p95_max_calls);
226
+ });
227
+ ```
228
+
229
+ ## LLM-as-judge for agent quality
230
+
231
+ Beyond mechanical trajectory matching, judge for:
232
+ - Was the agent's intermediate reasoning sound? (rubric: logical, evidence-based, non-hallucinated)
233
+ - Was the final user message appropriate? (rubric: tone, completeness, accuracy)
234
+ - Did the agent handle ambiguity well? (rubric: did it ask for clarification when needed?)
235
+
236
+ These are rung-4 evaluations on top of rung-1/2/3 outcome and trajectory checks.
237
+
238
+ ## Anti-patterns
239
+
240
+ - **Trajectory-only eval** → punishes creative paths; brittle to refactor; ignores real outcome.
241
+ - **Outcome-only eval without state assertion** → trusts the agent's word; misses ghost actions.
242
+ - **Strict trajectory mode when subset/superset would do** → false negatives every time the agent legitimately reorders.
243
+ - **No tool-budget tracking** → agent regresses to expensive paths; you don't notice until the bill spikes.
244
+ - **No `forbidden_calls` enumeration** → agent silently learns to call dangerous tools.
245
+
246
+ ## Tools
247
+
248
+ - `langchain-ai/agentevals` (MIT) — Python library implementing all four trajectory match modes + LLM-as-judge for trajectories. Source of the taxonomy above.
249
+ - `langsmith` — observability + eval orchestration; tracks experiments over time.
250
+ - Custom implementation — the modes above are ~50 lines each in any language.
251
+
252
+ The discipline isn't the library choice; it's choosing outcome-vs-trajectory deliberately, picking the right match mode, and tracking efficiency alongside accuracy.
@@ -0,0 +1,169 @@
1
+ # LLM-as-judge calibration — how to make rung 4 mean something
2
+
3
+ LLM-as-judge sounds simple: a model grades the output. In practice, without calibration it produces NUMBERS WITHOUT SIGNAL — judge scores drift with the model, with rubric phrasing, with prompt minutiae. You read "judge says 4.2 average" and have no idea if that means the system is good.
4
+
5
+ Calibration anchors the judge to human assessment. After calibration, a judge score has meaning. Before, it doesn't.
6
+
7
+ ## The three non-negotiables
8
+
9
+ ### 1. Calibrate against ≥20 human-graded cases
10
+
11
+ Process:
12
+
13
+ 1. Sample ≥20 cases from the reference dataset (or representative production traffic).
14
+ 2. Have ≥1 domain expert grade each case using the same rubric the judge will use. Multiple humans per case is better (inter-rater agreement is useful signal).
15
+ 3. Run the judge against the same cases.
16
+ 4. Compute Spearman rank correlation between human scores and judge scores.
17
+
18
+ **Target:** Spearman ≥0.80.
19
+ **Acceptable:** 0.70-0.80 with documented rationale (e.g., "subjective tone judgments inherently noisy").
20
+ **Reject:** <0.70. The judge is not measuring what you think it's measuring.
21
+
22
+ ### 2. Use a different model than the system under test
23
+
24
+ A model judging its own output produces false positives. The judge agrees with itself even when wrong because it shares the same biases and blind spots.
25
+
26
+ Pairing examples:
27
+ - System: GPT-4 → Judge: Claude Opus.
28
+ - System: Claude Sonnet → Judge: GPT-4o.
29
+ - System: Gemini → Judge: Claude.
30
+
31
+ If both system and judge MUST be from the same provider, at minimum use different model sizes (Sonnet judges Opus output, not vice versa).
32
+
33
+ ### 3. Structured rubric, not free-form scoring
34
+
35
+ "Rate this answer 1-10" → noise. Different runs give different scores; different humans disagree wildly; the score has no anchor.
36
+
37
+ Structured rubric: ≥3 criteria, each with a defined scale and an example per score point.
38
+
39
+ Example rubric for FAITHFULNESS (RAG):
40
+
41
+ ```markdown
42
+ # Faithfulness rubric (1-5 scale)
43
+
44
+ Score each answer against the retrieved context. A faithful answer makes claims supported by the context; an unfaithful one fabricates or extrapolates.
45
+
46
+ ## 1 — Severely unfaithful
47
+ The answer contains claims that contradict the context, or fabricates facts not present in any chunk. Example: context says "Q3 revenue was $1.2M"; answer says "Q3 revenue exceeded $5M."
48
+
49
+ ## 2 — Mostly unfaithful
50
+ The answer mixes context-supported and fabricated claims, where the fabrication is meaningful. Example: cites a study that wasn't in the context.
51
+
52
+ ## 3 — Mixed
53
+ Half the answer is grounded; half is reasonable inference or generalization beyond the context. Example: context describes the API; answer adds advice not derivable from context.
54
+
55
+ ## 4 — Mostly faithful
56
+ All claims are supported by context; minor paraphrasing or summarization without distortion. Example: rewords a passage accurately.
57
+
58
+ ## 5 — Strictly faithful
59
+ Every claim is directly traceable to a specific chunk; no information added beyond what context contains. Example: quotes-with-attribution style.
60
+ ```
61
+
62
+ Provide this rubric INSIDE the judge prompt. Free-form is forbidden.
63
+
64
+ ## The calibration loop
65
+
66
+ ```
67
+ 1. Sample 20-30 cases for calibration set.
68
+ 2. Human-grade them blind (without seeing other graders or judge).
69
+ 3. Run judge with rubric.
70
+ 4. Compute Spearman vs human scores.
71
+ 5. If <0.70:
72
+ - Examine disagreements: where does judge consistently miss?
73
+ - Refine rubric: more specific scale, more examples, narrower scope.
74
+ - OR switch judge model: try a different vendor/size.
75
+ - Re-run step 3-4.
76
+ 6. If 0.70-0.80: document the noise floor; accept with caveats.
77
+ 7. If ≥0.80: judge is calibrated. Save the rubric + judge config in version control.
78
+ ```
79
+
80
+ Calibration is one-time-per-config but RECURRING-PER-MODEL-CHANGE. Every model swap (you upgrade GPT-4 to GPT-5; vendor deprecates Opus 4.7) invalidates the calibration. Re-calibrate.
81
+
82
+ ## Judge drift monitoring
83
+
84
+ After deployment:
85
+ - Re-run calibration set monthly.
86
+ - Plot Spearman over time.
87
+ - Alert if Spearman drops below 0.75 between calibration runs — the judge has drifted (model update, rubric got stale, traffic distribution shifted).
88
+
89
+ ```
90
+ .dw/eval/judges/<feature>/
91
+ ├── rubric.md # the rubric, version-controlled
92
+ ├── calibration-2026-05-12.jsonl # 20+ cases with human + judge scores
93
+ ├── spearman-2026-05-12.txt # 0.84
94
+ ├── calibration-2026-08-12.jsonl # quarterly re-calibration
95
+ └── spearman-2026-08-12.txt # 0.81
96
+ ```
97
+
98
+ ## Rubric design patterns
99
+
100
+ ### DO
101
+
102
+ - **3-5 criteria** per rubric (one for each dimension you care about: faithfulness, completeness, tone, format, ...).
103
+ - **1-5 scale** with anchored descriptions per point (not 1-10 — too granular for reliable agreement).
104
+ - **Example per score point** showing the kind of output that earns that score.
105
+ - **Explicit "what to ignore"** — e.g., "ignore minor grammar; score on substance."
106
+
107
+ ### DON'T
108
+
109
+ - Single-criterion "quality" score — too vague to calibrate.
110
+ - 1-100 scales — humans can't reliably distinguish 73 from 76.
111
+ - Rubrics longer than 500 words — the judge skips and lazy-scores.
112
+ - "Holistic" scoring without breakdown — opaque to debug.
113
+
114
+ ## Multi-criterion rubrics
115
+
116
+ For complex outputs (RAG, agents), one number rarely captures quality. Use per-criterion scores:
117
+
118
+ ```json
119
+ {
120
+ "faithfulness": 4,
121
+ "completeness": 3,
122
+ "tone": 5,
123
+ "format": 5,
124
+ "overall": null
125
+ }
126
+ ```
127
+
128
+ Aggregate as needed downstream (weighted average, minimum, "all must be ≥3"). Don't have the judge compute the aggregate — bias compounds.
129
+
130
+ ## Anti-patterns
131
+
132
+ - **Judge with no rubric.** "Rate this 1-10." Numbers, no signal.
133
+ - **Judge is the system being tested.** False positives baked in.
134
+ - **No calibration evidence in PR.** "We added LLM-as-judge" — okay, what's the Spearman?
135
+ - **Rubric stuffed with all criteria in one prompt** → judge lazy-scores. Split into criterion-per-call if needed.
136
+ - **Calibration done once, never revisited.** Model upgrades silently break it. Re-calibrate monthly or per model swap.
137
+ - **Judge scoring its own scoring.** Recursive trust collapse.
138
+
139
+ ## Bias to watch
140
+
141
+ LLM judges have characteristic biases:
142
+
143
+ - **Length bias** — longer outputs score higher even when shorter is better. Normalize length in the rubric.
144
+ - **Self-similarity bias** — judges rate outputs that resemble their own writing higher. Cross-model pairing helps.
145
+ - **Position bias** (in comparative judging) — first item often wins. Randomize order, run both A/B and B/A.
146
+ - **Recency bias** — last item in context is overweighted. Vary order.
147
+ - **Sycophancy** — judges agree with strongly-stated input even when wrong. Frame the judge prompt neutrally.
148
+
149
+ Document which biases you tested for in the calibration write-up.
150
+
151
+ ## Cost discipline
152
+
153
+ LLM-as-judge can dominate eval costs. At $0.01-$0.10 per judgment, 100 cases × 4 rubric criteria × monthly = real money.
154
+
155
+ Optimizations (in order of impact):
156
+ 1. Run judge against SAMPLES, not the whole dataset every time. 50 random cases weekly catches regression.
157
+ 2. Use the cheapest model that maintains Spearman ≥0.80. GPT-4 mini may calibrate as well as GPT-4 for your rubric.
158
+ 3. Batch judge calls when the API supports it.
159
+ 4. Cache judge results per (input, output, rubric-version) tuple — same eval run shouldn't pay twice.
160
+ 5. Skip judge for cases where rungs 1-3 already failed — they're broken; no point asking subjective quality.
161
+
162
+ ## When NOT to use LLM-as-judge
163
+
164
+ - The output has a deterministic correct answer. Use rung 1 or 2.
165
+ - The output has a measurable side effect. Use rung 3.
166
+ - The team won't budget for calibration. The judge will produce noise.
167
+ - The rubric can't be written in <500 words. The criterion is too vague.
168
+
169
+ A poorly-calibrated judge is worse than no judge: it gives false confidence. Better to ship with "tested manually by domain expert on 20 cases" than with "judge score 4.1" that means nothing.