@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.
@@ -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
+