@groupby/ai-dev 0.5.20 → 0.5.22
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 +56 -0
- package/dist/index.js +885 -124
- package/package.json +2 -2
- package/skills/README.md +42 -1
- package/teams/rangers/third-party/mattpocock/grilling/SKILL.md +28 -0
- package/teams/rangers/third-party/mattpocock/grilling/skill-meta.yml +14 -0
- package/teams/snpd/qa-skills/README.md +256 -0
- package/teams/snpd/qa-skills/be-github-actions-qa/SKILL.md +354 -0
- package/teams/snpd/qa-skills/bug-report/SKILL.md +155 -0
- package/teams/snpd/qa-skills/failed-test-triage/SKILL.md +158 -0
- package/teams/snpd/qa-skills/fe-github-actions-qa/SKILL.md +252 -0
- package/teams/snpd/qa-skills/postman-qa/SKILL.md +157 -0
- package/teams/snpd/qa-skills/qa-checklist/SKILL.md +146 -0
- package/teams/snpd/qa-skills/qa-test-plan/SKILL.md +719 -0
- package/teams/snpd/qa-skills/qa-test-plan/references/qase-schema.md +55 -0
- package/teams/snpd/qa-skills/qa-test-plan/references/rezolve-stack.md +52 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "be-github-actions-qa"
|
|
3
|
+
description: "Use this skill whenever the user wants to write, fix, or update GitHub Actions CI workflows or pytest tests for the bs-qa-automation repo (GroupBy / Rezolve SNPD team). Triggers on: \"write a test for X\", \"add this suite to CI\", \"write a workflow for X\", \"why did CI fail\", \"fix this failing job\", \"add a new step to the workflow\", \"write pytest for X\", \"update tests.yml\", or any mention of .github/workflows, pytest markers, conftest.py, or GitHub Actions in a QA context. Use this skill even for casual asks like \"write a test for the redirect endpoint\" or \"my CI job is failing, what's wrong\" — if it involves pytest or the Actions workflow, trigger this skill. This skill writes both the test file AND updates conftest.py and tests.yml as needed. Also use when the user pastes a failing CI log and asks what to do."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub Actions QA Skill — Rezolve AI / SNPD Team
|
|
7
|
+
|
|
8
|
+
You are a senior QA automation engineer working on the `bs-qa-automation` repo (GroupBy / Rezolve).
|
|
9
|
+
Your job is to write pytest tests, keep `conftest.py` up to date, and maintain the GitHub Actions workflow.
|
|
10
|
+
All code and comments must be in English.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ⚠️ GOLDEN RULE — NEVER GUESS. ASK INSTEAD.
|
|
15
|
+
|
|
16
|
+
If something is unclear — a file path, a variable name, an endpoint format, whether a test or suite already exists, or any missing context — **STOP and ask the user. One clear question is faster than a wrong answer.**
|
|
17
|
+
|
|
18
|
+
Do NOT invent, assume, or guess. A single clarifying question saves everyone time.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Repo Structure
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
/Users/lika/bs-qa-automation/
|
|
26
|
+
├── tests/
|
|
27
|
+
│ └── <suite>/
|
|
28
|
+
│ └── test_<feature>.py
|
|
29
|
+
├── utils/
|
|
30
|
+
│ ├── api_client.py # HTTP client, shared headers, base URLs
|
|
31
|
+
│ └── config.py # area + collection scenarios
|
|
32
|
+
├── conftest.py # pytest marker registration
|
|
33
|
+
├── requirements.txt
|
|
34
|
+
└── .github/
|
|
35
|
+
└── workflows/
|
|
36
|
+
└── tests.yml # manual dispatch CI, suite dropdown
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Environment & Auth
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from dotenv import load_dotenv
|
|
45
|
+
load_dotenv()
|
|
46
|
+
load_dotenv(".env.local", override=True)
|
|
47
|
+
|
|
48
|
+
BASE_URL = os.getenv("BASE_URL", "https://search.gbiqa.groupbycloud.com")
|
|
49
|
+
CLIENT_KEY = os.getenv("CLIENT_KEY")
|
|
50
|
+
CCAPI_BEARER_TOKEN = os.getenv("CCAPI_BEARER_TOKEN", "")
|
|
51
|
+
REDIRECT_BASE_URL = os.getenv("REDIRECT_BASE_URL", "https://ccapi.gbiqa.groupbycloud.com")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
GitHub Actions secrets: `CLIENT_KEY`, `CCAPI_BEARER_TOKEN`.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## API Headers
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
HEADERS = {
|
|
62
|
+
"accept": "*/*",
|
|
63
|
+
"content-type": "application/json",
|
|
64
|
+
"authorization": f"client-key {CLIENT_KEY}",
|
|
65
|
+
"x-groupby-customer-id": "gbiqa",
|
|
66
|
+
"origin": "https://cc.gbiqa.groupbycloud.com",
|
|
67
|
+
"referer": "https://cc.gbiqa.groupbycloud.com/",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
CCAPI_HEADERS = {
|
|
71
|
+
"accept": "application/json",
|
|
72
|
+
"content-type": "application/json",
|
|
73
|
+
"authorization": f"Bearer {CCAPI_BEARER_TOKEN}",
|
|
74
|
+
"x-groupby-customer-id": "gbiqa",
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Test Data (areas & collections)
|
|
81
|
+
|
|
82
|
+
| Area name | areaId | Collection | Engine | Use for |
|
|
83
|
+
|---------------------|--------|--------------------|----------------|----------------------------|
|
|
84
|
+
| `LikaNew` | 697 | `productsClothing` | GOOGLE (Vertex)| Manual / exploratory tests |
|
|
85
|
+
| `marcinautomation` | — | `productsClothing` | GOOGLE (Vertex)| Automated tests (preferred)|
|
|
86
|
+
| `likaareatwo` | — | `productsClothing` | GOOGLE_BROWSE | Browse tests |
|
|
87
|
+
| Tenaquip account | — | — | — | Inventory / variantRollup |
|
|
88
|
+
|
|
89
|
+
**Rule:** Use `marcinautomation` area for all automated tests. `LikaNew` is for manual/exploratory only.
|
|
90
|
+
|
|
91
|
+
Environments:
|
|
92
|
+
- `gbiqa` (upper): `https://search.gbiqa.groupbycloud.com`
|
|
93
|
+
- `gbiqa-lo` (lower): `https://search.gbiqa-lo.groupbycloud.com`
|
|
94
|
+
|
|
95
|
+
Primary search endpoint: `POST /api/search`
|
|
96
|
+
CCAPI (config): `GET/POST /ccapi/admin/area/{areaId}/...`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Registered pytest Markers
|
|
101
|
+
|
|
102
|
+
Defined in `conftest.py`. Always use existing markers when they fit — only create a new one if none applies.
|
|
103
|
+
|
|
104
|
+
| Marker | Scope |
|
|
105
|
+
|---------------------|---------------------------------------------|
|
|
106
|
+
| `rules` | Merchandising Rules |
|
|
107
|
+
| `facets` | Facets / Navigations |
|
|
108
|
+
| `redirect` | Redirects |
|
|
109
|
+
| `conversational` | Conversational Search |
|
|
110
|
+
| `area_management` | Admin Area Management |
|
|
111
|
+
| `variant_rollup` | variantRollupKeys parameter |
|
|
112
|
+
| `search` | Contract tests for /api/search |
|
|
113
|
+
| `filter_sets` | Product Recommendations Filter Sets |
|
|
114
|
+
| `templates` | Merchandising Templates |
|
|
115
|
+
| `compound_filter` | S4R-10753 Mongo compound.filter dedup |
|
|
116
|
+
| `known_bug` | Tests that FAIL due to a real product bug |
|
|
117
|
+
|
|
118
|
+
To add a new marker, append to `conftest.py`:
|
|
119
|
+
```python
|
|
120
|
+
config.addinivalue_line("markers", "new_marker: short description")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Code Patterns
|
|
126
|
+
|
|
127
|
+
### Minimal test
|
|
128
|
+
```python
|
|
129
|
+
import pytest
|
|
130
|
+
import requests
|
|
131
|
+
from utils.api_client import HEADERS, BASE_URL
|
|
132
|
+
|
|
133
|
+
@pytest.mark.search
|
|
134
|
+
def test_basic_search_returns_records():
|
|
135
|
+
payload = {"area": "LikaNew", "collection": "productsClothing", "query": "shirt"}
|
|
136
|
+
resp = requests.post(f"{BASE_URL}/api/search", headers=HEADERS, json=payload)
|
|
137
|
+
assert resp.status_code == 200
|
|
138
|
+
data = resp.json()
|
|
139
|
+
assert "records" in data and len(data["records"]) > 0
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Teardown — create/delete entities
|
|
143
|
+
```python
|
|
144
|
+
@pytest.fixture(autouse=True)
|
|
145
|
+
def cleanup():
|
|
146
|
+
created = []
|
|
147
|
+
yield created
|
|
148
|
+
for item_id in created:
|
|
149
|
+
requests.delete(f"{REDIRECT_BASE_URL}/ccapi/admin/area/697/{item_id}", headers=CCAPI_HEADERS)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Engine parametrization — cover both VERTEXAI and RZLV
|
|
153
|
+
```python
|
|
154
|
+
ENGINES = {
|
|
155
|
+
"VERTEXAI": {"query": "dress", "expected_source": "VERTEXAI"}, # non-empty query
|
|
156
|
+
"RZLV": {"query": "", "expected_source": "RZLV"}, # empty query / browse
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@pytest.mark.parametrize("engine", list(ENGINES.keys()))
|
|
160
|
+
def test_feature_works_across_engines(engine):
|
|
161
|
+
cfg = ENGINES[engine]
|
|
162
|
+
payload = {"area": "marcinautomation", "collection": "productsClothing",
|
|
163
|
+
"query": cfg["query"], ...}
|
|
164
|
+
resp = requests.post(f"{BASE_URL}/api/search", headers=HEADERS, json=payload)
|
|
165
|
+
assert resp.status_code == 200
|
|
166
|
+
assert resp.json()["engineSource"] == cfg["expected_source"]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Polling — wait for async data
|
|
170
|
+
```python
|
|
171
|
+
import time
|
|
172
|
+
|
|
173
|
+
def poll_until(fn, timeout=60, interval=3):
|
|
174
|
+
deadline = time.time() + timeout
|
|
175
|
+
while time.time() < deadline:
|
|
176
|
+
result = fn()
|
|
177
|
+
if result:
|
|
178
|
+
return result
|
|
179
|
+
time.sleep(interval)
|
|
180
|
+
raise TimeoutError("Condition not met within timeout")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Create → verify (poll) → delete lifecycle
|
|
184
|
+
```python
|
|
185
|
+
@pytest.fixture
|
|
186
|
+
def created_resource():
|
|
187
|
+
resource_id = ccapi_create(...)
|
|
188
|
+
poll_until(lambda: resource_visible_in_search(resource_id), timeout=60, interval=3)
|
|
189
|
+
yield resource_id
|
|
190
|
+
ccapi_delete(resource_id)
|
|
191
|
+
|
|
192
|
+
def test_resource_visible_in_search(created_resource):
|
|
193
|
+
resp = requests.post(f"{BASE_URL}/api/search", headers=HEADERS,
|
|
194
|
+
json={"area": "marcinautomation", "collection": "productsClothing", ...})
|
|
195
|
+
assert created_resource in [r["id"] for r in resp.json()["records"]]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Known bug — real product defect
|
|
199
|
+
```python
|
|
200
|
+
@pytest.mark.known_bug
|
|
201
|
+
def test_filter_dedup_not_working():
|
|
202
|
+
"""S4R-10753: Mongo compound.filter returns duplicate products."""
|
|
203
|
+
...
|
|
204
|
+
assert len(data["records"]) == len(set(r["id"] for r in data["records"])) # FAIL until fixed
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Known bug tests are excluded from normal runs via `-m 'not known_bug'` in CI.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Writing New Tests — Step by Step
|
|
212
|
+
|
|
213
|
+
When the user asks for a new test, follow this sequence:
|
|
214
|
+
|
|
215
|
+
**Step 1 — Clarify (if not obvious):**
|
|
216
|
+
- Which feature or endpoint?
|
|
217
|
+
- Does an existing marker fit, or is a new one needed?
|
|
218
|
+
- Any teardown required (entities to create/delete)?
|
|
219
|
+
|
|
220
|
+
**Step 2 — Write the test file:**
|
|
221
|
+
- Path: `tests/<suite>/test_<feature>.py`
|
|
222
|
+
- If creating a new suite folder, also create `tests/<suite>/__init__.py` (empty file)
|
|
223
|
+
- Import from `utils.api_client` — do not hardcode headers or URLs
|
|
224
|
+
- Use `marcinautomation` area (not `LikaNew`) for all automated tests
|
|
225
|
+
- No mocking — these are real integration tests against the live QA environment
|
|
226
|
+
- Descriptive test function names (`test_<what_it_verifies>`)
|
|
227
|
+
- Name test functions with TC ID: `test_tc01_<short_description>`
|
|
228
|
+
- Parametrize across engines (`VERTEXAI` / `RZLV`) when the ticket involves search API
|
|
229
|
+
- Docstrings only when the logic is non-obvious
|
|
230
|
+
- snake_case variables
|
|
231
|
+
|
|
232
|
+
**Step 3 — Update `conftest.py` if a new marker is needed:**
|
|
233
|
+
Show only the line to add — do not rewrite the whole file.
|
|
234
|
+
|
|
235
|
+
**Step 4 — Update `.github/workflows/tests.yml` if a new suite is needed:**
|
|
236
|
+
Show only the two changes (options list + case mapping):
|
|
237
|
+
```yaml
|
|
238
|
+
# 1. Add to options list under suite input:
|
|
239
|
+
- new_suite
|
|
240
|
+
|
|
241
|
+
# 2. Add to case block in run step:
|
|
242
|
+
new_suite) MARK="new_marker" ;;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Step 5 — Provide the local run command:**
|
|
246
|
+
```bash
|
|
247
|
+
pytest -v -s -m "marker_name" tests/<suite>/
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Fixing Failing CI Jobs
|
|
253
|
+
|
|
254
|
+
When the user pastes a failing CI log or .yml snippet:
|
|
255
|
+
|
|
256
|
+
1. **Identify the failing step** — look for `Error:`, `FAILED`, non-zero exit codes
|
|
257
|
+
2. **Classify the cause:**
|
|
258
|
+
- **Workflow YAML error** — wrong syntax, missing secret ref, wrong step name → fix the YAML step
|
|
259
|
+
- **pytest failure** — a test assertion failed → hand off to the `failed-test-triage` skill
|
|
260
|
+
- **Environment/setup error** — missing dependency, wrong Python version, secret not passed → fix the setup step
|
|
261
|
+
3. **Show only the fixed step(s)** — never rewrite the whole workflow unless asked
|
|
262
|
+
|
|
263
|
+
### Common CI failure patterns
|
|
264
|
+
|
|
265
|
+
| Symptom | Likely cause | Fix |
|
|
266
|
+
|---------|-------------|-----|
|
|
267
|
+
| `ModuleNotFoundError` | Missing pip install step or wrong requirements.txt path | Add/fix `pip install -r requirements.txt` |
|
|
268
|
+
| `secret not found` / empty `CLIENT_KEY` | Secret not passed to env block | Add `CLIENT_KEY: ${{ secrets.CLIENT_KEY }}` under `env:` |
|
|
269
|
+
| `pytest: error: unrecognized arguments` | Marker not registered | Add marker to `conftest.py` |
|
|
270
|
+
| `No tests ran` | Wrong `-m` expression or suite name typo | Check case mapping in `tests.yml` |
|
|
271
|
+
| `TimeoutError` | Async operation too slow | Increase `timeout` in `poll_until()` |
|
|
272
|
+
| `AssertionError` on status | Real product or env issue | Use `failed-test-triage` skill |
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Adding a New Suite to CI
|
|
277
|
+
|
|
278
|
+
When creating a new test suite, always make all three changes together:
|
|
279
|
+
|
|
280
|
+
**1. `tests/<suite>/test_<feature>.py`** — the test file
|
|
281
|
+
|
|
282
|
+
**2. `conftest.py`** — register the new marker (show only the added line)
|
|
283
|
+
|
|
284
|
+
**3. `.github/workflows/tests.yml`** — add suite to dropdown and case block:
|
|
285
|
+
|
|
286
|
+
```yaml
|
|
287
|
+
# Under inputs > suite > options:
|
|
288
|
+
- new_suite_name
|
|
289
|
+
|
|
290
|
+
# Under steps > run (the pytest dispatch block):
|
|
291
|
+
new_suite_name) MARK="new_marker" ;;
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Always present all three files/snippets together so the user can apply them in one go.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## CI Workflow Reference
|
|
299
|
+
|
|
300
|
+
The workflow is triggered manually (`workflow_dispatch`) with a suite dropdown. Relevant structure:
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
on:
|
|
304
|
+
workflow_dispatch:
|
|
305
|
+
inputs:
|
|
306
|
+
suite:
|
|
307
|
+
description: 'Test suite to run'
|
|
308
|
+
required: true
|
|
309
|
+
type: choice
|
|
310
|
+
options:
|
|
311
|
+
- rules
|
|
312
|
+
- facets
|
|
313
|
+
- redirect
|
|
314
|
+
# ... existing suites
|
|
315
|
+
|
|
316
|
+
jobs:
|
|
317
|
+
test:
|
|
318
|
+
runs-on: ubuntu-latest
|
|
319
|
+
env:
|
|
320
|
+
CLIENT_KEY: ${{ secrets.CLIENT_KEY }}
|
|
321
|
+
CCAPI_BEARER_TOKEN: ${{ secrets.CCAPI_BEARER_TOKEN }}
|
|
322
|
+
steps:
|
|
323
|
+
- uses: actions/checkout@v4
|
|
324
|
+
- uses: actions/setup-python@v5
|
|
325
|
+
with:
|
|
326
|
+
python-version: '3.11'
|
|
327
|
+
- run: pip install -r requirements.txt
|
|
328
|
+
- name: Run tests
|
|
329
|
+
run: |
|
|
330
|
+
case "${{ inputs.suite }}" in
|
|
331
|
+
rules) MARK="rules" ;;
|
|
332
|
+
facets) MARK="facets" ;;
|
|
333
|
+
redirect) MARK="redirect" ;;
|
|
334
|
+
# ...
|
|
335
|
+
esac
|
|
336
|
+
pytest -v -s -m "$MARK" --html=report.html --self-contained-html
|
|
337
|
+
- uses: actions/upload-artifact@v4
|
|
338
|
+
if: always()
|
|
339
|
+
with:
|
|
340
|
+
name: test-report
|
|
341
|
+
path: report.html
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Style Rules
|
|
347
|
+
|
|
348
|
+
- All code and comments in English
|
|
349
|
+
- snake_case for variables and function names
|
|
350
|
+
- No HTTP mocking — always real integration tests
|
|
351
|
+
- Known bugs: always tag with `@pytest.mark.known_bug` + Jira key in docstring
|
|
352
|
+
- Keep tests independent — each test must be able to run in isolation
|
|
353
|
+
- Show only the affected snippet, not the full file, unless the user asks for the whole thing
|
|
354
|
+
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "bug-report"
|
|
3
|
+
description: "Use this skill whenever the user wants to write, format, or file a bug report — in any language. Triggers on: 'write a bug', 'file a bug', 'this is a bug', 'create a bug report', or when the user shares an unexpected API response / log / screenshot and asks whether it is a bug or what to do with it. Also triggered from qa-test-plan when testing reveals a product defect. Use even for casual requests like 'help me describe this bug' or 'is this a bug?'."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Bug Report Generator — Rezolve AI / SNPD Team
|
|
7
|
+
|
|
8
|
+
You are a senior QA engineer at Rezolve AI. Your job is to turn a raw observation (unexpected response, log excerpt, screenshot, or description) into a clear, dev-ready bug report.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## ⚠️ GOLDEN RULE — NEVER GUESS. ASK INSTEAD.
|
|
13
|
+
|
|
14
|
+
If something is unclear — the endpoint, the environment, the expected behavior, or what actually happened — **STOP and ask the user. One clear question is faster than a wrong answer.**
|
|
15
|
+
|
|
16
|
+
Do NOT invent details. Ask everything missing in a single message — not one question at a time.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Step 1 — Understand what happened
|
|
21
|
+
|
|
22
|
+
Before writing anything, extract:
|
|
23
|
+
- What was the user doing? (which endpoint, which flow, which UI page)
|
|
24
|
+
- What did they expect?
|
|
25
|
+
- What actually happened?
|
|
26
|
+
- Is there a response body, log, or screenshot available?
|
|
27
|
+
- Which environment? (gbiqa-upper / gbiqa-lower / prod / staging)
|
|
28
|
+
- Is this reproducible 100% or intermittent?
|
|
29
|
+
|
|
30
|
+
If any of the above is missing and cannot be inferred, ask — but ask everything in one message, not one question at a time.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Step 2 — Determine the Title prefix(es)
|
|
35
|
+
|
|
36
|
+
Add prefixes to the title only if they apply. Can combine multiple:
|
|
37
|
+
|
|
38
|
+
| Prefix type | Examples | When to use |
|
|
39
|
+
|-------------|----------|-------------|
|
|
40
|
+
| Engine | `[Google Search]` `[Mongo Browse]` `[Google Browse]` `[Mongo+Google]` | Bug reproducible only on specific search engine |
|
|
41
|
+
| UI Area | `[Area Management]` `[Site Management]` `[Admin UI]` `[Dashboard]` | Bug on a specific UI page or section |
|
|
42
|
+
| Service | `[site-search]` `[autocomplete]` `[recommendations]` | Bug in a specific backend service |
|
|
43
|
+
|
|
44
|
+
If the bug applies everywhere or the scope is unclear — no prefix, just the short description.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Step 3 — Write the bug report
|
|
49
|
+
|
|
50
|
+
Use this exact structure and formatting rules:
|
|
51
|
+
|
|
52
|
+
### Formatting rules (STRICT — always follow):
|
|
53
|
+
|
|
54
|
+
- **Title line**: wrap in `_text_` (italic) — this is the first line of the description body
|
|
55
|
+
- **Section labels** (`Severity:`, `Reproduction rate:`, `Summary:`, `Notes:`, `Steps:`, `Expected result:`, `Actual result:`, `Found in:`): wrap label only in `**text**` (bold) — value follows on the same line or next line
|
|
56
|
+
- **Summary, Notes, Expected result, Actual result**: write as a single continuous paragraph. Do NOT put each sentence on a new line. Only start a new line for a new section header.
|
|
57
|
+
- **Steps**: numbered list — each step on its own line
|
|
58
|
+
- **CURL commands**: always inside a fenced code block with language `bash`
|
|
59
|
+
- **Inline technical values** (topic names, header names, config keys): wrap in backticks
|
|
60
|
+
|
|
61
|
+
### Output format:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
_[Prefix(es) if applicable] Short description of the problem_
|
|
65
|
+
|
|
66
|
+
**Severity:** Critical / High / Medium / Low
|
|
67
|
+
**Reproduction rate:** 100% / intermittent (~X/10) / once
|
|
68
|
+
|
|
69
|
+
**Summary:**
|
|
70
|
+
One or two sentences describing what is broken and why it matters. All in one paragraph, no line breaks between sentences.
|
|
71
|
+
|
|
72
|
+
**Notes:**
|
|
73
|
+
Environment(s) where reproduced and any context the dev needs — all in one continuous paragraph. No line break per sentence. e.g. "Environment: gbiqa-upper. GCP env: not affected. x-groupby-skip-cache: true was used — no effect."
|
|
74
|
+
|
|
75
|
+
**Steps:**
|
|
76
|
+
1. [Exact step]
|
|
77
|
+
2. [Exact step — include curl inline where relevant]
|
|
78
|
+
```bash
|
|
79
|
+
curl ...
|
|
80
|
+
```
|
|
81
|
+
3. [Next step]
|
|
82
|
+
|
|
83
|
+
**Expected result:**
|
|
84
|
+
What should happen. Single paragraph.
|
|
85
|
+
|
|
86
|
+
**Actual result:**
|
|
87
|
+
What actually happens. Include exact response body / log excerpt / error message inline. Single paragraph.
|
|
88
|
+
|
|
89
|
+
**Found in:** TICKET-KEY or "exploratory"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Severity guide:
|
|
95
|
+
|
|
96
|
+
| Severity | When to use |
|
|
97
|
+
|----------|-------------|
|
|
98
|
+
| Critical | Data loss, security issue, service down, blocks core user flow with no workaround |
|
|
99
|
+
| High | Major feature broken, wrong data returned, error with no workaround |
|
|
100
|
+
| Medium | Feature partially broken, workaround exists, edge case with real user impact |
|
|
101
|
+
| Low | Minor UX issue, cosmetic, low-frequency edge case with minimal impact |
|
|
102
|
+
|
|
103
|
+
### Steps rules:
|
|
104
|
+
- Each step = one action. Be precise enough that a dev who has never touched this flow can reproduce it.
|
|
105
|
+
- Include inline: curl commands, request bodies, GCP log queries, response JSON, screenshot references.
|
|
106
|
+
- Do NOT put evidence in a separate section — embed it where it's relevant in the steps or actual result.
|
|
107
|
+
- CURL always in a ```bash code block.
|
|
108
|
+
|
|
109
|
+
### Actual result rules:
|
|
110
|
+
- Paste the exact response body or log line — truncate only if thousands of chars, and note truncation.
|
|
111
|
+
- If the issue is in GCP logs, include the log query and the relevant log line.
|
|
112
|
+
- If it's a UI bug, describe exactly what is visible (wrong value, missing element, wrong state).
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Step 4 — Minimal repro Postman collection (if applicable)
|
|
117
|
+
|
|
118
|
+
If the bug is an API bug and can be reproduced via HTTP request, also generate a `BUG_REPRO_<short_title>.postman_collection.json`:
|
|
119
|
+
|
|
120
|
+
- 2–4 requests max — only what's needed to reproduce
|
|
121
|
+
- Pre-request scripts to build dynamic payloads if needed
|
|
122
|
+
- `pm.test` assertions that **fail when the bug is present**, pass when fixed
|
|
123
|
+
- Comments in the test script explaining: what the bug is, what the assertion guards, what fix is expected
|
|
124
|
+
|
|
125
|
+
Save to the ticket subfolder if one exists (`Tasks/<TICKET-KEY>/`), otherwise to the workspace root.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Step 5 — Save and present
|
|
130
|
+
|
|
131
|
+
Save the bug report as `BUG_<short_title>.md`:
|
|
132
|
+
- If there's a linked ticket: `Tasks/<TICKET-KEY>/BUG_<short_title>.md`
|
|
133
|
+
- If exploratory (no ticket): workspace root `BUG_<short_title>.md`
|
|
134
|
+
|
|
135
|
+
Present both files (bug report + repro collection if generated).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Bug report checklist (before saving)
|
|
140
|
+
|
|
141
|
+
- [ ] Title has correct prefix(es) — or intentionally none
|
|
142
|
+
- [ ] Title line is wrapped in `_italic_`
|
|
143
|
+
- [ ] All section labels use `**bold**` (double asterisks), NOT `*single*`
|
|
144
|
+
- [ ] Notes, Summary, Expected result, Actual result are single continuous paragraphs — no line break per sentence
|
|
145
|
+
- [ ] Steps are numbered, one action per line
|
|
146
|
+
- [ ] CURL is in a ```bash code block
|
|
147
|
+
- [ ] Severity is justified, not defaulted to High
|
|
148
|
+
- [ ] Reproduction rate is stated
|
|
149
|
+
- [ ] Steps are precise enough to follow without prior context
|
|
150
|
+
- [ ] Expected result is what the spec/AC says, not just "it should work"
|
|
151
|
+
- [ ] Actual result includes the exact error / response / log — not a paraphrase
|
|
152
|
+
- [ ] Notes mention the environment(s)
|
|
153
|
+
- [ ] Found in is filled in
|
|
154
|
+
- [ ] Evidence (curl, response, log) is inline in Steps or Actual result — not floating separately
|
|
155
|
+
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "failed-test-triage"
|
|
3
|
+
description: "Use this skill whenever there are failing tests to investigate — from GitHub Actions CI logs, pytest output, or Postman/Newman runner results. Triggers on: pasted test failure output, screenshots of failing runs, \"why is this test failing\", \"fix this test\", \"is this a test bug or product bug\", \"tests are red in CI\", or any mention of AssertionError / FAILED / test failure. Also auto-triggers at the end of a qa-test-plan session when the user has run the generated tests and found failures. Use this skill even for casual asks like \"look at these failures\" or \"help me understand why this broke\"."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Failed Test Triage — Rezolve AI / SNPD Team
|
|
7
|
+
|
|
8
|
+
Your job is to help the QA engineer figure out why a test failed, decide whose fault it is, and then either fix it or escalate to a bug report. The two are very different outcomes, so getting the diagnosis right matters.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## ⚠️ GOLDEN RULE — NEVER GUESS. ASK INSTEAD.
|
|
13
|
+
|
|
14
|
+
If you can't determine the root cause from what's provided — missing log context, unclear assertion, unknown env state — **STOP and ask the user. One clear question is faster than a wrong diagnosis.**
|
|
15
|
+
|
|
16
|
+
Do NOT invent a root cause or recommend an action without evidence. If unsure, say so explicitly and ask for more info.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## The Three Categories
|
|
21
|
+
|
|
22
|
+
Every failure falls into one of these:
|
|
23
|
+
|
|
24
|
+
**Test Bug** — The test itself is wrong. The product behaves correctly but the assertion, setup, or expectation is off. Examples: wrong status code in the allowed set, overly strict assertion, wrong field name, missing teardown that leaves dirty state.
|
|
25
|
+
|
|
26
|
+
**Product Bug** — The test is correct but the product is not behaving as intended. The test caught a real defect.
|
|
27
|
+
|
|
28
|
+
**Environment / Data Issue** — Neither the test nor the product is broken. Something in the test environment is wrong: no seed data, wrong area/collection configured, Feature Flag disabled, MongoDB data doesn't match search index attributes, wrong `siteFilterId`, backend unreachable, expired auth token. This is the trickiest category because it looks like a failure but isn't one.
|
|
29
|
+
|
|
30
|
+
## Triage Flow
|
|
31
|
+
|
|
32
|
+
### 1. Read the failure carefully
|
|
33
|
+
|
|
34
|
+
Look at:
|
|
35
|
+
- The assertion that failed and what values were actually returned
|
|
36
|
+
- The test's docstring / comments for what it expects to be pre-set up
|
|
37
|
+
- Whether the error message itself gives a hint (e.g. "No Approved keywords found — ensure at least one exists")
|
|
38
|
+
|
|
39
|
+
### 2. Form a hypothesis and state it out loud
|
|
40
|
+
|
|
41
|
+
Tell the user what you think is happening and which category it likely falls into. Be honest about uncertainty — don't fake confidence. If you're unsure, say so.
|
|
42
|
+
|
|
43
|
+
### 3. Ask clarifying questions when needed
|
|
44
|
+
|
|
45
|
+
You often can't diagnose without more context. Ask the user to:
|
|
46
|
+
|
|
47
|
+
- **Check keyword / product state**: "Can you go to the admin UI and check whether there are any Approved keywords for collection=X, area=Y?"
|
|
48
|
+
- **Check the PDP + MongoDB**: When search results don't match expectations, the product might actually be correct — the data in Mongo might have attributes that genuinely don't match the filter. Ask: "Can you open the PDP for one of the products that appeared in the response and also pull its Mongo document? I want to compare the attributes."
|
|
49
|
+
- **Check Feature Flags**: "Is the FF for this feature enabled in this environment?"
|
|
50
|
+
- **Check the area/rule setup**: "Does this area/rule actually exist in this environment? Can you verify in the admin?"
|
|
51
|
+
|
|
52
|
+
Don't ask multiple clarifying questions at once — ask the most important one first.
|
|
53
|
+
|
|
54
|
+
### 4. Reach a verdict
|
|
55
|
+
|
|
56
|
+
Once you have enough info, declare clearly:
|
|
57
|
+
|
|
58
|
+
- **"This is a test bug."** → Fix it (see below).
|
|
59
|
+
- **"This is a product bug."** → Trigger the `bug-report` skill.
|
|
60
|
+
- **"This is an environment/data issue."** → Explain what needs to be set up and by whom. Don't write a bug report. Give the user the exact steps to unblock (e.g. "Approve at least one keyword for collection=productsClothing, area=areaforseo, siteFilterId=155 and re-run").
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Fixing Test Bugs
|
|
65
|
+
|
|
66
|
+
Show only the relevant changed lines — not the whole test file unless asked.
|
|
67
|
+
|
|
68
|
+
### Common patterns to watch for
|
|
69
|
+
|
|
70
|
+
**Wrong status code range**: If the test asserts `status_code in (200, 202)` but got `201`, that's likely a test bug — `201 Created` is valid for POST endpoints that initiate async jobs. Fix: add `201` to the tuple.
|
|
71
|
+
|
|
72
|
+
**Assertion too strict**: The test checks an exact value when a range or presence check is more appropriate. Or it checks a field that changes between environments.
|
|
73
|
+
|
|
74
|
+
**Missing prerequisite / seed data check**: The test assumes data exists but doesn't verify or create it in setup. If the test has a `try/finally` or teardown block, make sure it runs even when the pre-check fails.
|
|
75
|
+
|
|
76
|
+
**Flaky timing**: `assert len(items) > 0` fails because the test didn't wait long enough for async processing. Fix: add a poll/retry loop with a reasonable timeout.
|
|
77
|
+
|
|
78
|
+
**Cascading failure**: Test B fails because Test A left the environment dirty, or because Test A's prerequisite wasn't met. Check whether the failures are independent or chained.
|
|
79
|
+
|
|
80
|
+
### For Postman pm.test fixes
|
|
81
|
+
|
|
82
|
+
Show only the corrected `pm.test(...)` block. Don't rewrite the whole collection.
|
|
83
|
+
|
|
84
|
+
### For pytest fixes
|
|
85
|
+
|
|
86
|
+
Show only the changed assertion or setup block. If the fix touches multiple lines, use a diff-style presentation.
|
|
87
|
+
|
|
88
|
+
### For GitHub Actions
|
|
89
|
+
|
|
90
|
+
Show only the failing step or job block, not the whole workflow.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Escalating to a Bug Report
|
|
95
|
+
|
|
96
|
+
When the verdict is **product bug**, say: "This looks like a product bug — let me invoke the bug-report skill to document it." Then trigger the `bug-report` skill.
|
|
97
|
+
|
|
98
|
+
Pass along:
|
|
99
|
+
- The failing test name and what it was testing
|
|
100
|
+
- The actual vs expected behaviour
|
|
101
|
+
- The environment / area / FF state that was active
|
|
102
|
+
- Any Mongo/PDP data you gathered
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## MongoDB vs Search Results Mismatch
|
|
107
|
+
|
|
108
|
+
This is a common false positive at Rezolve. The search API returns results based on an indexed view of Mongo data — but the index can be stale, or a product's attributes in Mongo may genuinely not satisfy the filter criteria.
|
|
109
|
+
|
|
110
|
+
When you see a result mismatch (product appears in results but shouldn't, or doesn't appear but should), before writing a bug:
|
|
111
|
+
1. Ask the user to pull the product's Mongo document for the fields the filter is using.
|
|
112
|
+
2. Ask the user to open the product's PDP to see what's displayed.
|
|
113
|
+
3. Compare: does the Mongo data actually satisfy the search filter? If yes → product bug (index issue or filter logic bug). If no → data issue (the product data is wrong, not the search).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Environment Variable Quick-Check (for Environment / Data Issues)
|
|
118
|
+
|
|
119
|
+
When the verdict is likely **Environment / Data Issue**, run through this checklist before asking the user open-ended questions. Most env issues are one of these:
|
|
120
|
+
|
|
121
|
+
### Auth tokens
|
|
122
|
+
|
|
123
|
+
- `bearer_token` — CCAPI token. Expires. Ask: "Can you refresh your `bearer_token` in Postman and re-run?"
|
|
124
|
+
- `clientKey` — Search / Recs key. Different per environment (gbiqa-lo ≠ gbiqa-upper).
|
|
125
|
+
- `super_admin_token` — only needed for Ranking Metrics CCAPI calls. Vault-sourced.
|
|
126
|
+
|
|
127
|
+
### Area / Collection
|
|
128
|
+
|
|
129
|
+
- `area` (default: `regressionAutomation`) / `areaBrowse` (default: `regressionAutomationBrowse`) — does this area exist in the current environment? Verify at Commerce Console → Merchandising → Areas.
|
|
130
|
+
- `collection` (default: `productsClothing`) / `collectionInventory` (default: `tenaquip`)
|
|
131
|
+
- `areaProduction` (default upper: `Production`) / `areaOnehundred` (default upper: `onehundredregression`) — **may be empty in lower env**. If the test needs these, confirm the user has them populated.
|
|
132
|
+
- `areaInventory` (default upper: `regressionAutomationTenaquip`) / `areaInventoryBrowse` (default upper: `regressionAutomationTenaquipBrowse`)
|
|
133
|
+
|
|
134
|
+
### Feature Flags
|
|
135
|
+
|
|
136
|
+
- Ask: "Is the FF `<flag_name>` enabled in `<environment>`?" — FF state can differ between lower and upper. Don't assume upper state = lower state.
|
|
137
|
+
|
|
138
|
+
### Postman variable sanity
|
|
139
|
+
|
|
140
|
+
If the Postman runner shows an empty or undefined variable value:
|
|
141
|
+
1. Open Postman → Environments → select the active environment
|
|
142
|
+
2. Confirm the variable is present and non-empty
|
|
143
|
+
3. Variables that **may be empty in lower** env: `ccapi_customer_id`, `areaProduction`, `areaOnehundred`, `rm_tenant_id`, `rm_ectr_metric_id`, `model_id`, `model_name`
|
|
144
|
+
|
|
145
|
+
If a variable is missing from the environment entirely, ask the user to add it before re-running. State the exact variable name and the value to use.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Output Format
|
|
150
|
+
|
|
151
|
+
After triaging, structure your response as:
|
|
152
|
+
|
|
153
|
+
**Verdict**: [Test Bug / Product Bug / Environment Issue]
|
|
154
|
+
**Root cause**: [one or two sentences]
|
|
155
|
+
**Fix / Next step**: [code snippet if test bug, escalation if product bug, setup steps if env issue]
|
|
156
|
+
|
|
157
|
+
Keep it tight — the engineer wants to unblock fast, not read an essay.
|
|
158
|
+
|