@brunosps00/dev-workflow 0.11.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.
- package/README.md +54 -5
- package/lib/constants.js +20 -20
- package/lib/init.js +24 -1
- package/lib/migrate-skills.js +129 -0
- package/lib/removed-bundled-skills.js +16 -0
- package/lib/uninstall.js +6 -2
- package/lib/utils.js +43 -1
- package/package.json +1 -1
- package/scaffold/en/agent-instructions.md +68 -0
- package/scaffold/en/commands/dw-autopilot.md +1 -1
- package/scaffold/en/commands/dw-brainstorm.md +1 -1
- package/scaffold/en/commands/dw-bugfix.md +4 -3
- package/scaffold/en/commands/dw-code-review.md +1 -0
- package/scaffold/en/commands/dw-create-tasks.md +6 -0
- package/scaffold/en/commands/dw-create-techspec.md +1 -1
- package/scaffold/en/commands/dw-deps-audit.md +1 -1
- package/scaffold/en/commands/dw-fix-qa.md +1 -1
- package/scaffold/en/commands/dw-functional-doc.md +2 -2
- package/scaffold/en/commands/dw-help.md +2 -2
- package/scaffold/en/commands/dw-redesign-ui.md +7 -7
- package/scaffold/en/commands/dw-run-qa.md +5 -4
- package/scaffold/en/commands/dw-run-task.md +2 -2
- package/scaffold/en/templates/constitution-template.md +1 -1
- package/scaffold/pt-br/agent-instructions.md +68 -0
- package/scaffold/pt-br/commands/dw-autopilot.md +1 -1
- package/scaffold/pt-br/commands/dw-brainstorm.md +1 -1
- package/scaffold/pt-br/commands/dw-bugfix.md +4 -3
- package/scaffold/pt-br/commands/dw-code-review.md +1 -0
- package/scaffold/pt-br/commands/dw-create-tasks.md +6 -0
- package/scaffold/pt-br/commands/dw-create-techspec.md +1 -1
- package/scaffold/pt-br/commands/dw-deps-audit.md +1 -1
- package/scaffold/pt-br/commands/dw-fix-qa.md +1 -1
- package/scaffold/pt-br/commands/dw-functional-doc.md +2 -2
- package/scaffold/pt-br/commands/dw-help.md +2 -2
- package/scaffold/pt-br/commands/dw-redesign-ui.md +7 -7
- package/scaffold/pt-br/commands/dw-run-qa.md +5 -4
- package/scaffold/pt-br/commands/dw-run-task.md +2 -2
- package/scaffold/pt-br/templates/constitution-template.md +1 -1
- package/scaffold/skills/dw-council/SKILL.md +1 -1
- package/scaffold/skills/dw-incident-response/SKILL.md +164 -0
- package/scaffold/skills/dw-incident-response/references/blameless-discipline.md +126 -0
- package/scaffold/skills/dw-incident-response/references/communication-templates.md +107 -0
- package/scaffold/skills/dw-incident-response/references/postmortem-template.md +133 -0
- package/scaffold/skills/dw-incident-response/references/runbook-templates.md +169 -0
- package/scaffold/skills/dw-incident-response/references/severity-and-triage.md +186 -0
- package/scaffold/skills/dw-llm-eval/SKILL.md +148 -0
- package/scaffold/skills/dw-llm-eval/references/agent-eval.md +252 -0
- package/scaffold/skills/dw-llm-eval/references/judge-calibration.md +169 -0
- package/scaffold/skills/dw-llm-eval/references/oracle-ladder.md +171 -0
- package/scaffold/skills/dw-llm-eval/references/rag-metrics.md +186 -0
- package/scaffold/skills/dw-llm-eval/references/reference-dataset.md +190 -0
- package/scaffold/skills/dw-testing-discipline/SKILL.md +171 -0
- package/scaffold/skills/dw-testing-discipline/references/agent-guardrails.md +170 -0
- package/scaffold/skills/dw-testing-discipline/references/anti-patterns.md +336 -0
- package/scaffold/skills/dw-testing-discipline/references/core-rules.md +128 -0
- package/scaffold/skills/dw-testing-discipline/references/flaky-discipline.md +163 -0
- package/scaffold/skills/dw-testing-discipline/references/patterns.md +241 -0
- package/scaffold/skills/dw-testing-discipline/references/playwright-recipes.md +282 -0
- package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/security-boundary.md +1 -1
- package/scaffold/skills/dw-ui-discipline/SKILL.md +150 -0
- package/scaffold/skills/dw-ui-discipline/references/accessibility-floor.md +225 -0
- package/scaffold/skills/dw-ui-discipline/references/curated-defaults.md +195 -0
- package/scaffold/skills/dw-ui-discipline/references/hard-gate.md +162 -0
- package/scaffold/skills/dw-ui-discipline/references/state-matrix.md +101 -0
- package/scaffold/skills/dw-ui-discipline/references/visual-slop.md +152 -0
- package/scaffold/skills/ui-ux-pro-max/LICENSE +0 -21
- package/scaffold/skills/ui-ux-pro-max/SKILL.md +0 -659
- package/scaffold/skills/ui-ux-pro-max/data/_sync_all.py +0 -414
- package/scaffold/skills/ui-ux-pro-max/data/app-interface.csv +0 -31
- package/scaffold/skills/ui-ux-pro-max/data/charts.csv +0 -26
- package/scaffold/skills/ui-ux-pro-max/data/colors.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/design.csv +0 -1776
- package/scaffold/skills/ui-ux-pro-max/data/draft.csv +0 -1779
- package/scaffold/skills/ui-ux-pro-max/data/google-fonts.csv +0 -1924
- package/scaffold/skills/ui-ux-pro-max/data/icons.csv +0 -106
- package/scaffold/skills/ui-ux-pro-max/data/landing.csv +0 -35
- package/scaffold/skills/ui-ux-pro-max/data/products.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/scaffold/skills/ui-ux-pro-max/data/stacks/angular.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/astro.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/scaffold/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/laravel.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/scaffold/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/scaffold/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/scaffold/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/scaffold/skills/ui-ux-pro-max/data/stacks/threejs.csv +0 -54
- package/scaffold/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/scaffold/skills/ui-ux-pro-max/data/styles.csv +0 -85
- package/scaffold/skills/ui-ux-pro-max/data/typography.csv +0 -74
- package/scaffold/skills/ui-ux-pro-max/data/ui-reasoning.csv +0 -162
- package/scaffold/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/scaffold/skills/ui-ux-pro-max/scripts/core.py +0 -262
- package/scaffold/skills/ui-ux-pro-max/scripts/design_system.py +0 -1148
- package/scaffold/skills/ui-ux-pro-max/scripts/search.py +0 -114
- package/scaffold/skills/ui-ux-pro-max/skills/brand/SKILL.md +0 -97
- package/scaffold/skills/ui-ux-pro-max/skills/design/SKILL.md +0 -302
- package/scaffold/skills/ui-ux-pro-max/skills/design-system/SKILL.md +0 -244
- package/scaffold/skills/ui-ux-pro-max/templates/base/quick-reference.md +0 -297
- package/scaffold/skills/ui-ux-pro-max/templates/base/skill-content.md +0 -358
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/agent.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/augment.json +0 -18
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/claude.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/codebuddy.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/codex.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/continue.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/copilot.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/cursor.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/droid.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/gemini.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/kilocode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/kiro.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/opencode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/qoder.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/roocode.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/trae.json +0 -21
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/warp.json +0 -18
- package/scaffold/skills/ui-ux-pro-max/templates/platforms/windsurf.json +0 -21
- package/scaffold/skills/webapp-testing/SKILL.md +0 -138
- package/scaffold/skills/webapp-testing/assets/test-helper.js +0 -56
- /package/scaffold/skills/{webapp-testing → dw-testing-discipline}/references/three-workflow-patterns.md +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# RAG evaluation — three orthogonal metrics
|
|
2
|
+
|
|
3
|
+
Retrieval-augmented generation (RAG) has three failure modes, each requiring its own metric. Measure all three. Measuring only one creates blindspots.
|
|
4
|
+
|
|
5
|
+
## The three metrics
|
|
6
|
+
|
|
7
|
+
### 1. Retrieval precision@k
|
|
8
|
+
|
|
9
|
+
**What it measures:** of the top-K chunks retrieved, how many were RELEVANT to the user's query?
|
|
10
|
+
|
|
11
|
+
**How to compute:**
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
def precision_at_k(retrieved_chunk_ids, relevant_chunk_ids, k=5):
|
|
15
|
+
top_k = retrieved_chunk_ids[:k]
|
|
16
|
+
relevant_in_top_k = sum(1 for cid in top_k if cid in relevant_chunk_ids)
|
|
17
|
+
return relevant_in_top_k / k
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Reference data needed:** for each test case, the human-labeled set of "chunks that should have been retrieved" — the ground truth.
|
|
21
|
+
|
|
22
|
+
**Target:** depends on K. For k=5, target precision >0.6 (3 of 5 chunks relevant). For k=10, target >0.5.
|
|
23
|
+
|
|
24
|
+
**What it catches:** retrieval is bringing back junk. Chunk embeddings are wrong, the index is stale, the query rewriting is broken.
|
|
25
|
+
|
|
26
|
+
**What it misses:** the LLM may still produce a great answer even from imperfect retrieval — or a hallucinated answer despite perfect retrieval. Pair with metrics #2 and #3.
|
|
27
|
+
|
|
28
|
+
### 2. Answer faithfulness
|
|
29
|
+
|
|
30
|
+
**What it measures:** does the answer make claims that are SUPPORTED by the retrieved context? Or does it fabricate?
|
|
31
|
+
|
|
32
|
+
**How to compute (rung-4 LLM-as-judge with rubric):**
|
|
33
|
+
|
|
34
|
+
The judge sees: user question + retrieved context + generated answer. Scores 1-5 per the faithfulness rubric (see `judge-calibration.md` for an example).
|
|
35
|
+
|
|
36
|
+
**Reference data needed:** the retrieved context (saved from the run) and the answer. No ground-truth answer required — the judge checks claim-by-claim against the context.
|
|
37
|
+
|
|
38
|
+
**Target:** 80% of cases score ≥4 on the 1-5 scale.
|
|
39
|
+
|
|
40
|
+
**What it catches:** hallucination — the answer says things the context didn't support. This is the #1 failure mode in production RAG.
|
|
41
|
+
|
|
42
|
+
**What it misses:** the answer might be faithful to the retrieved context but the retrieved context might be WRONG. Pair with metric #1.
|
|
43
|
+
|
|
44
|
+
### 3. Context utilization
|
|
45
|
+
|
|
46
|
+
**What it measures:** did the answer USE the retrieved context, or ignore it and produce a generic / parametric-memory response?
|
|
47
|
+
|
|
48
|
+
**How to compute (heuristic + LLM-as-judge hybrid):**
|
|
49
|
+
|
|
50
|
+
Heuristic part — n-gram overlap or semantic similarity:
|
|
51
|
+
```python
|
|
52
|
+
def context_overlap(answer, context, n=3):
|
|
53
|
+
answer_ngrams = set(ngrams(answer, n))
|
|
54
|
+
context_ngrams = set(ngrams(context, n))
|
|
55
|
+
if not answer_ngrams:
|
|
56
|
+
return 0
|
|
57
|
+
return len(answer_ngrams & context_ngrams) / len(answer_ngrams)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Judge part — ask if the answer would change materially without the context:
|
|
61
|
+
> "If the retrieved context were removed, would the answer be substantially different? 1 = same as without context (didn't use it), 5 = fully context-grounded."
|
|
62
|
+
|
|
63
|
+
**Target:** 70%+ overlap on substantive answers; judge score ≥4 on 80% of cases.
|
|
64
|
+
|
|
65
|
+
**What it catches:** the answer is faithful to the context (metric #2 passes) but ignores it — the model used its parametric memory instead. This means retrieval is doing nothing.
|
|
66
|
+
|
|
67
|
+
**What it misses:** the answer might use the context but cite it incorrectly. Pair with metric #2.
|
|
68
|
+
|
|
69
|
+
## Why all three are needed
|
|
70
|
+
|
|
71
|
+
| Metric | Detects | Misses |
|
|
72
|
+
|--------|---------|--------|
|
|
73
|
+
| Retrieval precision@k | Junk in retrieval | Faithfulness; utilization |
|
|
74
|
+
| Answer faithfulness | Hallucination | Retrieval quality; whether context was used |
|
|
75
|
+
| Context utilization | Ignoring retrieval | Hallucination beyond context; retrieval quality |
|
|
76
|
+
|
|
77
|
+
A RAG system can fail in all three independent ways. Measuring only one creates blind spots in the other two.
|
|
78
|
+
|
|
79
|
+
## Combined metric example
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
def evaluate_rag(case):
|
|
83
|
+
retrieved = retrieve(case.query)
|
|
84
|
+
answer = generate(case.query, retrieved)
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
'precision_at_5': precision_at_k(
|
|
88
|
+
[c.id for c in retrieved],
|
|
89
|
+
case.relevant_chunk_ids,
|
|
90
|
+
k=5
|
|
91
|
+
),
|
|
92
|
+
'faithfulness': llm_judge_faithfulness(
|
|
93
|
+
query=case.query,
|
|
94
|
+
context=retrieved,
|
|
95
|
+
answer=answer
|
|
96
|
+
),
|
|
97
|
+
'context_utilization_overlap': context_overlap(answer, retrieved),
|
|
98
|
+
'context_utilization_judge': llm_judge_utilization(
|
|
99
|
+
query=case.query,
|
|
100
|
+
context=retrieved,
|
|
101
|
+
answer=answer
|
|
102
|
+
),
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Aggregate per-case scores into the per-run summary:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Run 2026-05-12:
|
|
110
|
+
precision@5: 0.68 (target >0.6) ✓
|
|
111
|
+
faithfulness ≥4: 83% (target >80%) ✓
|
|
112
|
+
context utilization: 72% (target >70%) ✓
|
|
113
|
+
Overall: PASS
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Common RAG failure modes
|
|
117
|
+
|
|
118
|
+
| Symptom | Likely metric that catches it |
|
|
119
|
+
|---------|------------------------------|
|
|
120
|
+
| User says "the bot is making stuff up" | Faithfulness |
|
|
121
|
+
| User says "the bot didn't see my documents" | Context utilization (or retrieval precision) |
|
|
122
|
+
| User says "the bot is bad at finding things" | Retrieval precision@k |
|
|
123
|
+
| User says "the answer is correct but ignores recent updates" | Retrieval recall (precision's partner — different metric) |
|
|
124
|
+
| User says "the bot gives the same generic answer no matter what I ask" | Context utilization |
|
|
125
|
+
| User says "the bot says the doc says X but it doesn't" | Faithfulness |
|
|
126
|
+
|
|
127
|
+
The metric points at the layer to fix. Without it, debugging is guesswork.
|
|
128
|
+
|
|
129
|
+
## Retrieval recall (the fourth metric, conditional)
|
|
130
|
+
|
|
131
|
+
Precision asks "of what we retrieved, how much was good?" Recall asks "of what was good, how much did we retrieve?"
|
|
132
|
+
|
|
133
|
+
In production RAG with many candidate chunks, recall is often the limiting factor — the right chunk exists in the index but doesn't surface.
|
|
134
|
+
|
|
135
|
+
Compute:
|
|
136
|
+
```python
|
|
137
|
+
def recall_at_k(retrieved_chunk_ids, relevant_chunk_ids, k=5):
|
|
138
|
+
top_k = set(retrieved_chunk_ids[:k])
|
|
139
|
+
return len(top_k & set(relevant_chunk_ids)) / len(relevant_chunk_ids)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Track recall when:
|
|
143
|
+
- The corpus is large (>1000 chunks per query domain).
|
|
144
|
+
- Users report "the bot can't find things that exist in our docs."
|
|
145
|
+
- You're tuning the retrieval pipeline (chunking strategy, embedding model, search algorithm).
|
|
146
|
+
|
|
147
|
+
Skip recall when:
|
|
148
|
+
- The corpus is small (top-K = ~10% of the corpus; recall is high by default).
|
|
149
|
+
- Precision is the dominant problem.
|
|
150
|
+
|
|
151
|
+
## Dataset structure for RAG
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"id": "rag-case-001",
|
|
156
|
+
"query": "What's our PTO policy for sabbatical years?",
|
|
157
|
+
"expected": {
|
|
158
|
+
"relevant_chunk_ids": ["chunk-policy-pto-2024", "chunk-policy-sabbatical"],
|
|
159
|
+
"expected_answer_themes": ["accrual rate", "carryover limits", "sabbatical exception"],
|
|
160
|
+
"should_cite": true
|
|
161
|
+
},
|
|
162
|
+
"metadata": {
|
|
163
|
+
"source": "production-2026-04-12-support-thread-S-892",
|
|
164
|
+
"difficulty": "medium",
|
|
165
|
+
"tags": ["pto-policy", "sabbatical", "rare-query"]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The `relevant_chunk_ids` field requires human labeling — domain expert reviews the corpus, identifies which chunks SHOULD surface for that query.
|
|
171
|
+
|
|
172
|
+
## Anti-patterns
|
|
173
|
+
|
|
174
|
+
- **Measuring only one metric** (usually faithfulness via LLM-as-judge) → blind to retrieval and utilization failures.
|
|
175
|
+
- **No human-labeled relevance** → can't compute precision/recall.
|
|
176
|
+
- **Treating retrieval and generation as one black box** → can't tell which layer regressed.
|
|
177
|
+
- **Eval set drawn only from "easy" queries** → metrics are good in test, terrible in production.
|
|
178
|
+
- **Ignoring recent-information bias** (RAG must use retrieval; parametric memory is stale) → context utilization metric catches this.
|
|
179
|
+
|
|
180
|
+
## Tooling
|
|
181
|
+
|
|
182
|
+
- **ragas** (open source) implements precision, recall, faithfulness, and other RAG metrics with LLM judges. Use as reference implementation.
|
|
183
|
+
- **Custom implementation** is straightforward — the metrics above are <100 lines of Python each.
|
|
184
|
+
- **LangSmith / Weights & Biases** wrap eval runs with tracking but don't replace the core metrics.
|
|
185
|
+
|
|
186
|
+
The discipline isn't tool choice; it's measuring all three orthogonal dimensions every run.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Reference dataset — 20 from failures beats 200 perfect
|
|
2
|
+
|
|
3
|
+
The dataset is the bedrock. Without one, every "improvement" is anecdote and every regression goes unnoticed until users complain. With one, you can measure change.
|
|
4
|
+
|
|
5
|
+
## The 20-from-failures principle
|
|
6
|
+
|
|
7
|
+
> 20 unambiguous cases drawn from real production failures beat 200 synthetic perfect cases.
|
|
8
|
+
|
|
9
|
+
Why:
|
|
10
|
+
- Synthetic cases reflect what the team IMAGINED would happen — they cover the cases the team already knows about.
|
|
11
|
+
- Production failures reflect what ACTUALLY happens — they cover blind spots and edge cases.
|
|
12
|
+
- 20 well-curated cases at the right level of difficulty discriminate models better than 200 average-difficulty cases.
|
|
13
|
+
|
|
14
|
+
A 20-case dataset is enough to:
|
|
15
|
+
- Detect regressions of >10% accuracy.
|
|
16
|
+
- Calibrate LLM-as-judge.
|
|
17
|
+
- Run cheaply enough to evaluate on every PR.
|
|
18
|
+
|
|
19
|
+
Scale up only when you've validated that 20 is producing useful signal.
|
|
20
|
+
|
|
21
|
+
## Where cases come from
|
|
22
|
+
|
|
23
|
+
In rough order of priority:
|
|
24
|
+
|
|
25
|
+
1. **Real production failures.** User reported a bug, support escalated a case, error logs show an unexpected output. Each becomes a case. Sanitize PII before saving.
|
|
26
|
+
2. **Edge cases discovered during development.** "Oh, what if the user asks X?" — add it.
|
|
27
|
+
3. **Adversarial examples.** Inputs designed to trip the system (prompt injection, ambiguity, contradiction). Especially important for chat/RAG.
|
|
28
|
+
4. **Boundary inputs.** Empty, very long, special characters, mixed languages, unusual encodings.
|
|
29
|
+
5. **Synthetic — last resort.** Only when no real input exists yet (e.g., pre-launch). Mark them as synthetic; replace as production data arrives.
|
|
30
|
+
|
|
31
|
+
Target distribution: **80% real production-sourced**, 20% adversarial/boundary. Pure-synthetic datasets give pure-synthetic confidence.
|
|
32
|
+
|
|
33
|
+
## Case structure
|
|
34
|
+
|
|
35
|
+
Each case is one line in `cases.jsonl`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"id": "case-001",
|
|
40
|
+
"input": {
|
|
41
|
+
"user_message": "I want to cancel my subscription",
|
|
42
|
+
"user_context": { "tier": "premium", "tenure_months": 18 }
|
|
43
|
+
},
|
|
44
|
+
"expected": {
|
|
45
|
+
"intent": "cancellation_request",
|
|
46
|
+
"should_offer_retention": true,
|
|
47
|
+
"tone_targets": ["empathetic", "non-manipulative"]
|
|
48
|
+
},
|
|
49
|
+
"rubric_criteria": ["faithfulness", "tone", "completeness"],
|
|
50
|
+
"metadata": {
|
|
51
|
+
"source": "production-2026-04-12-ticket-T-1234",
|
|
52
|
+
"added_at": "2026-04-15",
|
|
53
|
+
"added_by": "@bruno",
|
|
54
|
+
"difficulty": "medium",
|
|
55
|
+
"tags": ["cancellation", "retention", "premium-user"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Fields:
|
|
61
|
+
|
|
62
|
+
- **`id`** — stable identifier (you'll reference it in regression reports).
|
|
63
|
+
- **`input`** — what the system receives. Match the production input shape exactly.
|
|
64
|
+
- **`expected`** — for rungs 1-3, the deterministic expected output or state change. For rung 4, the rubric-target (what a 5/5 answer would do).
|
|
65
|
+
- **`rubric_criteria`** — which rubric dimensions this case exercises.
|
|
66
|
+
- **`metadata.source`** — provenance. Production ticket? Synthetic? Adversarial?
|
|
67
|
+
- **`metadata.difficulty`** — easy/medium/hard. Track score by difficulty bucket.
|
|
68
|
+
- **`metadata.tags`** — for filtering ("show me cases that exercise retention logic").
|
|
69
|
+
|
|
70
|
+
## Dataset layout
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
.dw/eval/datasets/<feature-name>/
|
|
74
|
+
├── README.md # provenance, sample size, last review, change log
|
|
75
|
+
├── cases.jsonl # the cases themselves
|
|
76
|
+
├── rubric.md # the rubric used for rung-4 scoring
|
|
77
|
+
├── runs/
|
|
78
|
+
│ ├── 2026-05-01.jsonl # one line per case with scores from that run
|
|
79
|
+
│ ├── 2026-05-08.jsonl
|
|
80
|
+
│ └── ...
|
|
81
|
+
├── calibration/
|
|
82
|
+
│ ├── 2026-05-12-human-scores.jsonl
|
|
83
|
+
│ └── spearman-2026-05-12.txt
|
|
84
|
+
└── changelog.md # when cases were added/removed and why
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Everything is committed. Datasets evolve with the feature; the git history shows when and why.
|
|
88
|
+
|
|
89
|
+
## README.md template
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
# Reference dataset — <feature name>
|
|
93
|
+
|
|
94
|
+
**Purpose:** evaluate <feature> for <quality dimensions>.
|
|
95
|
+
|
|
96
|
+
**Current size:** N cases (X production-sourced, Y adversarial, Z synthetic).
|
|
97
|
+
|
|
98
|
+
**Difficulty distribution:** easy: A, medium: B, hard: C.
|
|
99
|
+
|
|
100
|
+
**Last reviewed:** YYYY-MM-DD.
|
|
101
|
+
|
|
102
|
+
**Maintainers:** @name1, @name2.
|
|
103
|
+
|
|
104
|
+
## When to expand
|
|
105
|
+
|
|
106
|
+
Add a case when:
|
|
107
|
+
- A new production failure is observed (always — that's the primary signal).
|
|
108
|
+
- A new edge case is identified during development.
|
|
109
|
+
- A new adversarial pattern is discovered (security review, red-team session).
|
|
110
|
+
|
|
111
|
+
Do NOT add cases just to inflate the count. The 20-from-failures principle: quality over quantity.
|
|
112
|
+
|
|
113
|
+
## When to retire a case
|
|
114
|
+
|
|
115
|
+
Retire (don't delete) when:
|
|
116
|
+
- The behavior the case checked is no longer relevant (feature removed).
|
|
117
|
+
- The case became trivially passing across all model versions (it's no longer discriminating).
|
|
118
|
+
|
|
119
|
+
Move retired cases to `cases-retired.jsonl` with a `retired_reason`.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Adding cases from production
|
|
123
|
+
|
|
124
|
+
Process:
|
|
125
|
+
|
|
126
|
+
1. **Capture the failure** — paste the actual input that failed in `cases-pending.jsonl`.
|
|
127
|
+
2. **Sanitize PII** — replace names, emails, IDs, account numbers with realistic-but-fake equivalents. NEVER commit real user data.
|
|
128
|
+
3. **Define expected behavior** — what SHOULD have happened. Get sign-off from a domain expert if subjective.
|
|
129
|
+
4. **Categorize** — difficulty, tags, rubric criteria.
|
|
130
|
+
5. **Promote** to `cases.jsonl` after review.
|
|
131
|
+
|
|
132
|
+
## Sampling for regression runs
|
|
133
|
+
|
|
134
|
+
You don't need to re-run the entire dataset every time. Smart sampling:
|
|
135
|
+
|
|
136
|
+
- **PR-time:** random sample of 30% + all "high difficulty" cases + any case added in the last 30 days. Fast feedback.
|
|
137
|
+
- **Pre-merge to main:** full dataset.
|
|
138
|
+
- **Nightly:** full dataset + judge re-calibration check.
|
|
139
|
+
- **Pre-deploy:** full dataset + manual eyeball on 10 random outputs.
|
|
140
|
+
|
|
141
|
+
## Detecting drift
|
|
142
|
+
|
|
143
|
+
After each run, compare against the prior run on the SAME cases:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Run 2026-05-08 vs 2026-05-01:
|
|
147
|
+
faithfulness: 4.2 → 3.9 (-0.3) ⚠ regression
|
|
148
|
+
completeness: 4.0 → 4.1 (+0.1)
|
|
149
|
+
tone: 4.5 → 4.4 (-0.1)
|
|
150
|
+
outcome accuracy: 95% → 92% ⚠ regression
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Two ways drift happens:
|
|
154
|
+
1. **Code change degraded quality** — your model swap or prompt tweak hurt something. Bisect.
|
|
155
|
+
2. **Judge drift** — the LLM-as-judge itself changed (vendor updated the model). Re-calibrate; the "regression" may be the judge, not the system.
|
|
156
|
+
|
|
157
|
+
## Dataset versioning
|
|
158
|
+
|
|
159
|
+
When the dataset materially changes (cases added/removed in batch, rubric updated), bump a version in the README:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Dataset version: 2.3
|
|
163
|
+
- v2.3 (2026-05-12): added 8 cases from production tickets in last 30 days
|
|
164
|
+
- v2.2 (2026-04-15): retired 3 cases that became trivially passing
|
|
165
|
+
- v2.1 (2026-03-20): rubric updated to add "completeness" criterion
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Each run logs which dataset version it ran against. You can't compare a v1 score to a v3 score directly.
|
|
169
|
+
|
|
170
|
+
## Cost discipline
|
|
171
|
+
|
|
172
|
+
- Keep the dataset SMALL on purpose. 20-50 cases for most features. 100+ only if the feature has many categorically different inputs.
|
|
173
|
+
- Cheap evaluations (rungs 1-3) run on every case every time.
|
|
174
|
+
- Expensive evaluations (rung 4) run on samples — 20-50 random cases — except for full pre-deploy runs.
|
|
175
|
+
|
|
176
|
+
## Anti-patterns
|
|
177
|
+
|
|
178
|
+
- **Synthetic-only dataset.** No connection to real production. Confidence isn't real.
|
|
179
|
+
- **Dataset grew to 500 cases nobody re-reads.** Half are duplicates; half are no longer discriminating. Audit and prune.
|
|
180
|
+
- **Cases without expected behavior.** "Just look at the output." No measurement possible.
|
|
181
|
+
- **Dataset not committed.** Lives in a notebook; ephemeral; lost when person leaves.
|
|
182
|
+
- **No metadata tracking source.** Can't tell synthetic from real; can't audit dataset quality.
|
|
183
|
+
- **Dataset reused across features.** Each feature has its own dataset; one-size-fits-all is one-size-fits-none.
|
|
184
|
+
|
|
185
|
+
## Cross-reference
|
|
186
|
+
|
|
187
|
+
- `oracle-ladder.md` — what to assert per case.
|
|
188
|
+
- `judge-calibration.md` — how to make rung-4 judgments meaningful.
|
|
189
|
+
- `rag-metrics.md` — RAG-specific extras for the dataset structure.
|
|
190
|
+
- `agent-eval.md` — agent-specific extras (trajectory matching).
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dw-testing-discipline
|
|
3
|
+
description: Use when authoring, reviewing, or debugging tests — enforces six core rules (assert behavior, push to lowest layer, fix prod first on red, real systems gate merge, mutation > coverage, no test backdoors), a catalog of anti-patterns, agent-authoring guardrails, and flaky-test discipline so tests reveal bugs instead of decorating CI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing Discipline
|
|
7
|
+
|
|
8
|
+
## Founding principle
|
|
9
|
+
|
|
10
|
+
> Tests exist to expose defects, not to keep CI green.
|
|
11
|
+
> A test that fails has done its job.
|
|
12
|
+
> A test that passes for the wrong reason is worse than no test.
|
|
13
|
+
|
|
14
|
+
Everything else in this skill follows from that.
|
|
15
|
+
|
|
16
|
+
## The six core rules
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
1. Test the behavior, never the mock.
|
|
20
|
+
2. Push each test to the lowest layer that can detect the defect.
|
|
21
|
+
3. When a test fails, read production first — change the test only with documented justification.
|
|
22
|
+
4. Real systems gate the merge. Mocks isolate; they do not validate.
|
|
23
|
+
5. Coverage is a flashlight; mutation score is a quality probe. Neither is a target.
|
|
24
|
+
6. No test-only methods, branches, or flags leak into production code.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Each rule has nuance read `references/core-rules.md` for the long version with examples.
|
|
28
|
+
|
|
29
|
+
## When to use
|
|
30
|
+
|
|
31
|
+
- Authoring any test (unit, integration, contract, E2E).
|
|
32
|
+
- Reviewing a PR diff under test paths.
|
|
33
|
+
- Debugging a flaky test (or considering retry-as-fix — read `references/flaky-discipline.md` first).
|
|
34
|
+
- Generating tests via an AI agent → invokes `references/agent-guardrails.md` automatically.
|
|
35
|
+
- Browser-based E2E with Playwright → recipes in `references/playwright-recipes.md`.
|
|
36
|
+
- Verifying browser-side trust boundaries (auth, CSRF, headers) → `references/security-boundary.md`.
|
|
37
|
+
- Picking which test workflow applies (UI / network / perf) → `references/three-workflow-patterns.md`.
|
|
38
|
+
|
|
39
|
+
## Reference router
|
|
40
|
+
|
|
41
|
+
| Doing what | Read |
|
|
42
|
+
|------------|------|
|
|
43
|
+
| Placing a new test (which layer?) | `references/core-rules.md` (Rule 2 deep-dive) |
|
|
44
|
+
| Writing new tests | `references/patterns.md` |
|
|
45
|
+
| Reviewing tests / spotting smells | `references/anti-patterns.md` |
|
|
46
|
+
| Agent-generated tests | `references/agent-guardrails.md` + `references/anti-patterns.md` |
|
|
47
|
+
| Flaky tests | `references/flaky-discipline.md` |
|
|
48
|
+
| Playwright E2E | `references/playwright-recipes.md` |
|
|
49
|
+
| Browser trust boundary | `references/security-boundary.md` |
|
|
50
|
+
| Picking the right workflow | `references/three-workflow-patterns.md` |
|
|
51
|
+
|
|
52
|
+
## Patterns that produce reliable tests (one-liners; full in `references/patterns.md`)
|
|
53
|
+
|
|
54
|
+
1. Query by behavior and accessible role; never CSS selectors or DOM indices.
|
|
55
|
+
2. Selector ladder: role → label → text → test-id → structural. Stop at the highest rung that disambiguates.
|
|
56
|
+
3. Wait on observable conditions; never wall-clock sleeps.
|
|
57
|
+
4. Each test independent and order-free; lean on `beforeEach`, not `beforeAll`.
|
|
58
|
+
5. One behavior per test; as many assertions as that behavior requires.
|
|
59
|
+
6. Names read as specifications: `should <outcome> when <condition> given <state>`.
|
|
60
|
+
7. Table-driven / parameterized when inputs vary.
|
|
61
|
+
8. Build test data via factories; literal blobs only for fields under test.
|
|
62
|
+
9. Mock at boundaries you don't control; real wiring for the systems you own.
|
|
63
|
+
10. Real systems gate the final merge; contract tests bridge unit and E2E.
|
|
64
|
+
11. Mutation score, not coverage percentage, measures suite strength.
|
|
65
|
+
12. Page Object Model is a tool; collapse it for small suites where it adds noise.
|
|
66
|
+
|
|
67
|
+
## Anti-pattern catalog (four families, full in `references/anti-patterns.md`)
|
|
68
|
+
|
|
69
|
+
The four kinds of smell that produce most test debt:
|
|
70
|
+
|
|
71
|
+
**A. Fragile to refactor** — tests bound to internals, not behavior:
|
|
72
|
+
- Implementation-detail selectors.
|
|
73
|
+
- Asserting internal structure instead of observable outcome.
|
|
74
|
+
- Testing private methods directly.
|
|
75
|
+
- Snapshots replacing real assertions.
|
|
76
|
+
- Vague existence assertions (`toBeTruthy`, `should('exist')`).
|
|
77
|
+
- Actions with no assertion ("clicking save works").
|
|
78
|
+
|
|
79
|
+
**B. Non-deterministic outcomes** — tests that flip verdict on the same code:
|
|
80
|
+
- Static sleeps / fixed-timeout waits.
|
|
81
|
+
- Test order dependency / hidden shared state.
|
|
82
|
+
- Non-deterministic inputs (clock, RNG, locale).
|
|
83
|
+
|
|
84
|
+
**C. Mock-driven false confidence** — tests testing the test setup:
|
|
85
|
+
- Asserting the mock exists.
|
|
86
|
+
- Mock drift (mocked response no longer matches real API).
|
|
87
|
+
- Over-mocking child components.
|
|
88
|
+
- Incomplete mocks (missing fields the code reads).
|
|
89
|
+
- Mocking the wrong level (mocking methods of the SUT itself).
|
|
90
|
+
- Asserting on a value the test body fed into a mock.
|
|
91
|
+
|
|
92
|
+
**D. Suite hygiene problems** — team and suite-level pathologies:
|
|
93
|
+
- Coverage as vanity metric.
|
|
94
|
+
- Happy-path-only coverage.
|
|
95
|
+
- Eternal `beforeAll` hiding dependencies.
|
|
96
|
+
- Cleanup in `afterEach` (move to `beforeEach`).
|
|
97
|
+
- Magic strings and logic in tests.
|
|
98
|
+
- Testing against third-party sites.
|
|
99
|
+
- Quarantine-as-cemetery (skip without owner or deadline).
|
|
100
|
+
- Retry-as-fix (auto-retry hiding real bugs).
|
|
101
|
+
- Duplicate tests across pyramid layers.
|
|
102
|
+
- Weakening assertions to make tests pass.
|
|
103
|
+
|
|
104
|
+
Total: 25 specific patterns across the four families.
|
|
105
|
+
|
|
106
|
+
## Agent-authoring guardrails (mandatory when an LLM writes tests)
|
|
107
|
+
|
|
108
|
+
Six guardrails block the most common failure modes when an LLM produces test code. Each is a pre-condition before the diff goes to review. Full prompts and verification in `references/agent-guardrails.md`:
|
|
109
|
+
|
|
110
|
+
1. **State the invariant first** — agent prints `INVARIANT`, `OWNING_LAYER`, `EXISTING_SUITE` before writing code.
|
|
111
|
+
2. **Extend, don't sprawl** — agent extends an existing suite; new files require a named invariant.
|
|
112
|
+
3. **Real execution somewhere** — at least one test path runs against real systems before merge.
|
|
113
|
+
4. **Red? Read production** — on failure, the agent reads production code first and prints `ANALYSIS:` before changing tests.
|
|
114
|
+
5. **Classify before snapshot** — snapshots only with explicit `PRODUCT_CONTRACT` classification; `IMPLEMENTATION_DETAIL` forbids them.
|
|
115
|
+
6. **Negative companion** — every positive assertion ships with a negative test for invalid input or failure mode.
|
|
116
|
+
|
|
117
|
+
## Placement doctrine (tripwires)
|
|
118
|
+
|
|
119
|
+
Before writing test code:
|
|
120
|
+
|
|
121
|
+
- Name the invariant in **one sentence**. Fuzzy language signals unclear requirements — stop and clarify.
|
|
122
|
+
- Place the test at the **lowest layer** capable of detecting the defect when the invariant breaks.
|
|
123
|
+
- Reject tests where (`likelihood-of-bug` × `blast-radius`) falls below a ten-minute-maintenance threshold (the test is more expensive to maintain than the bug would be to fix).
|
|
124
|
+
|
|
125
|
+
## Flaky discipline (tripwires)
|
|
126
|
+
|
|
127
|
+
- Quarantine flaky tests within ONE HOUR of detection. Assign a named owner within 24 hours with a fix-by date.
|
|
128
|
+
- Track `flaky_rate` as a first-class metric: SLO under 1–2%; alert at >5%.
|
|
129
|
+
- Real systems at the final gate: mock at unit; contract-test boundaries; real DB/queue/route at integration; near-zero mocks at E2E.
|
|
130
|
+
|
|
131
|
+
Full taxonomy in `references/flaky-discipline.md`.
|
|
132
|
+
|
|
133
|
+
## Cross-cutting red flags
|
|
134
|
+
|
|
135
|
+
Any of these in a PR is enough to REJECT a verdict:
|
|
136
|
+
|
|
137
|
+
- Mock setup larger than the test logic.
|
|
138
|
+
- Test breaks when an internal method is renamed (not the public contract).
|
|
139
|
+
- Removing the assertion body leaves the test green.
|
|
140
|
+
- Test fails when run with `.only` in isolation.
|
|
141
|
+
- `sleep`, `Thread.sleep`, or `cy.wait(<number>)` appears.
|
|
142
|
+
- Selector contains CSS class, index, or `xpath`.
|
|
143
|
+
- Test asserts a third-party site is reachable.
|
|
144
|
+
- Snapshot diffs accepted without reading.
|
|
145
|
+
- Coverage percentage is the only metric quoted.
|
|
146
|
+
- Failing tests auto-retried until green; no investigation.
|
|
147
|
+
- Skipped/quarantined tests without named owner and fix-by date.
|
|
148
|
+
- Test depends on `new Date()`, `Math.random()`, or system locale.
|
|
149
|
+
- `afterEach` resets database state.
|
|
150
|
+
- Agent-written test has 6+ assertions and zero edge cases.
|
|
151
|
+
- The diff contains the phrase "I'll mock this to be safe."
|
|
152
|
+
|
|
153
|
+
## When NOT to use this skill
|
|
154
|
+
|
|
155
|
+
- General code review unrelated to tests.
|
|
156
|
+
- Library-specific debugging where the test is just a reproduction.
|
|
157
|
+
- Non-testing CI pipeline design (deploys, artifacts, secrets).
|
|
158
|
+
- Production observability and alerting.
|
|
159
|
+
- Single-line typo fixes in existing tests.
|
|
160
|
+
|
|
161
|
+
## Integration with dev-workflow commands
|
|
162
|
+
|
|
163
|
+
- `/dw-create-tasks` applies the placement doctrine — each test-adding task names the invariant.
|
|
164
|
+
- `/dw-run-task` runs the 6 agent guardrails when generating tests during implementation.
|
|
165
|
+
- `/dw-code-review` runs the anti-pattern checks on diff hunks under test paths.
|
|
166
|
+
- `/dw-fix-qa` applies the flaky-discipline taxonomy in retest cycles.
|
|
167
|
+
- `/dw-run-qa` (UI mode) references `playwright-recipes.md` for concrete recipes.
|
|
168
|
+
|
|
169
|
+
## Bottom line
|
|
170
|
+
|
|
171
|
+
> A test that cannot fail is decorative. A test that fails for the wrong reason is misleading. Build tests that fail for exactly one reason — the reason the invariant was violated — and trust them when they do. Mocks isolate. Real systems validate. Coverage shines a light. Mutation score grades the suite. Agents will reach for the mock and the snapshot; the guardrails make them put both down. Tests reveal bugs, not just pass.
|