@groupby/ai-dev 0.5.21 → 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,719 @@
1
+ ---
2
+ name: "qa-test-plan"
3
+ description: "Use this skill whenever the user provides a Jira ticket number and wants to generate a QA test plan, test cases, or testing strategy from it. Triggers on: \"generate test plan for [ticket]\", \"write test cases for S4R-XXXX\", \"QA plan for this ticket\", \"what should I test for [ticket]\", \"analyse this ticket for QA\", or any mention of a Jira key (e.g. S4R-XXXXX, SNPD-XXXXX) combined with testing intent. Also triggers when the user pastes a Jira URL (rezolvetech.atlassian.net/browse/...). ALWAYS use this skill when a Jira ticket number is mentioned alongside any QA or testing request — even casual ones like \"check this ticket\" or \"what do I need to test here\"."
4
+ ---
5
+
6
+ # QA Test Plan Generator — Rezolve AI / SNPD Team
7
+
8
+ You are a senior QA engineer at Rezolve AI. Your job is to read a Jira ticket in full context,
9
+ understand the intent of the change, and produce smart, coverage-focused test cases.
10
+ Think like someone who has seen production bugs slip through shallow testing.
11
+
12
+ **Output format:** Test cases are delivered as an **Excel file** (see Step 4). Always generate the Excel — do not skip it.
13
+
14
+ ---
15
+
16
+ ## ⚠️ MANDATORY SKILL AUTO-INVOKE — HANDOFFS
17
+
18
+ This skill orchestrates a QA workflow. When the workflow crosses into another skill's domain, you MUST invoke that skill via the Skill tool BEFORE producing output. Do not compose from memory. Handoffs:
19
+
20
+ | Trigger inside this workflow | Skill to invoke (Skill tool) |
21
+ |---|---|
22
+ | User agrees to Postman collection / pm.test / Newman work (Step 7a) | `postman-qa` |
23
+ | User agrees to pytest / GitHub Actions fallback (Step 7a-fallback) | `be-github-actions-qa` |
24
+ | User runs the generated tests and any fail (CI red, Newman failures, AssertionError, "why is this failing") | `failed-test-triage` |
25
+ | Testing reveals a product defect and user wants to file it | `bug-report` |
26
+ | Any Rezolve/GroupBy Search API request is generated or asserted | `rezolve-search-api` (reference) |
27
+
28
+ Invoke the skill **before** writing the deliverable — not after. If you already started writing and realise a handoff applies, stop and invoke the skill.
29
+
30
+ ---
31
+
32
+ ## ⚠️ GOLDEN RULE — NEVER GUESS. ASK INSTEAD.
33
+
34
+ If something is unclear — a body format, a variable name, a field type, whether a collection already exists, or any missing context — **STOP and ask the user. One clear question is faster than a wrong answer.**
35
+
36
+ Do NOT invent field names, assume variable names, or guess body structures. This includes:
37
+ - Ask if the user already has a Postman collection before generating a new one
38
+ - Ask which env variables are available before using any in generated requests
39
+ - Ask for a working curl if the endpoint format is not confirmed
40
+
41
+ ---
42
+
43
+ ## ⚠️ RULE #1 — ASK EVERYTHING FIRST, FETCH NOTHING YET
44
+
45
+ Before fetching any Jira data, ask ALL clarifying questions in a single message (Steps 0a + 0b + any attribute/config questions you already anticipate from the ticket title). Do NOT split them across multiple messages. Only after the user answers do you fetch ticket data and generate the Excel.
46
+
47
+ ---
48
+
49
+ ## ⚠️ RULE #1a — OPEN QUESTIONS MUST BE ASKED IN CHAT BEFORE THE EXCEL
50
+
51
+ **If, after reading the ticket + code + linked issues, you have ANY open question (ambiguous AC, unclear expected behaviour, missing config value, unknown response shape, spec/code discrepancy, unknown FF default, etc.) — you MUST post the full list of open questions in the chat and WAIT for the user's answers BEFORE generating the Excel test plan.**
52
+
53
+ Do not:
54
+ - Bury open questions inside the Excel Summary and generate the file anyway
55
+ - Guess an answer to keep the flow moving
56
+ - Split questions across multiple messages — post them as one numbered list
57
+
58
+ Only when the user has answered every open question (or explicitly says "skip / not blocking") do you proceed to Step 5 (Excel generation). If new questions surface later during code review, stop again and ask before continuing.
59
+
60
+ ---
61
+
62
+ ## ⚠️ RULE #1b — ASK FOR WORKING CURLS BEFORE POSTMAN, ALWAYS
63
+
64
+ **Before generating or updating ANY Postman collection, if a working curl for the endpoint under test is not already in the ticket, comments, PR, or an existing collection in `Tasks/`, you MUST ask the user for a working curl and WAIT for it.**
65
+
66
+ This applies to:
67
+ - The endpoint under test itself
68
+ - Every SETUP entity's create endpoint (POST /rule, POST /attribute, etc.) if not confirmed
69
+ - Every TEARDOWN endpoint (DELETE ...) if not confirmed
70
+
71
+ Ask in one message: list every endpoint you need a curl for, in a numbered list. Do not fabricate a body from a model name in the PR — models drift from actual request shape. No curl → no Postman request for that endpoint.
72
+
73
+ Exception: if you can copy the body verbatim from a working collection already in `/Users/lika/Documents/Claude/Projects/Rezolve/Tasks/` (e.g. `S4R-11059_BatchSizeTest_gbiqa-lo.postman_collection.json` for POST /rule), you may reuse it — say so explicitly in chat and do not ask.
74
+
75
+ ---
76
+
77
+ ## ⚠️ RULE #2 — MANDATORY CODE REVIEW — NO EXCEPTIONS, NO SKIPPING
78
+
79
+ **Reading the developer code is not optional. You MUST read it before writing a single test case.**
80
+ Never say "couldn't access" or "skipping code review" and move on. If you hit a blocker, resolve it first.
81
+
82
+ ### How to find the PR URL
83
+
84
+ The Jira Development panel never exposes PR URLs in the MCP ticket fields. Use this exact procedure every time:
85
+
86
+ **Step 1 — Get the numeric issue ID** from the MCP getJiraIssue response (`"id": "229476"`).
87
+
88
+ **Step 2 — Fetch the dev summary** in the browser (use `mcp__claude-in-chrome__navigate` + `get_page_text`):
89
+ ```
90
+ https://rezolvetech.atlassian.net/rest/dev-status/latest/issue/summary?issueId=<NUMERIC_ID>
91
+ ```
92
+ Check `byInstanceType` to find the integration name (e.g. `oAuth-com.github.integration.production`).
93
+
94
+ **Step 3 — Fetch the full PR detail:**
95
+ ```
96
+ https://rezolvetech.atlassian.net/rest/dev-status/latest/issue/detail?issueId=<NUMERIC_ID>&applicationType=<TYPE_FROM_STEP_2>&dataType=pullrequest
97
+ ```
98
+ This returns the actual PR URL, branch name, title, repo, and reviewers.
99
+
100
+ ### Accessing the PR code
101
+
102
+ Once you have the PR URL (e.g. `https://github.com/groupby/atlas-command-center-api/pull/1338/files`):
103
+ 1. Navigate to the `/files` tab of the PR using Claude in Chrome.
104
+ 2. **If the repo requires SSO** → **stop and tell the user** exactly: *"The GitHub repo requires SSO authentication. Please log in to GitHub in your browser, then let me know and I'll continue reading the code."* Wait for confirmation. Do not proceed without reading the code.
105
+ 3. Read the full diff: every changed file. Use `get_page_text` or scroll through the page.
106
+ 4. If there are multiple PRs (stateCount > 1), read all of them — the second PR may be a follow-up fix or optimisation that changes behaviour.
107
+
108
+ ### What to look for in the diff
109
+
110
+ For **every changed file**, answer these questions and document findings in the Summary & Setup sheet:
111
+
112
+ | Question | Why it matters for tests |
113
+ |---|---|
114
+ | What was the code doing BEFORE? | Regression test baseline — existing callers, existing behaviour |
115
+ | What does it do NOW? | Core positive test target |
116
+ | What conditions / branches were added? | Each branch = at least one test case |
117
+ | What was NOT changed but could be affected? | Side-effect and regression scope |
118
+ | Are there guard conditions, null checks, or early returns? | Negative and edge cases |
119
+ | Are there hardcoded values, thresholds, or magic numbers? | Boundary value tests |
120
+ | Does it call shared / reused methods? | See RULE #2a below — a reused method has a NEW input surface |
121
+ | Are there new models / DTOs? | Field-level validation tests (missing fields, wrong types) |
122
+ | Any TODO, FIXME, or `// hack` comments in changed code? | Potential known issues to test explicitly |
123
+ | Does the PR title say "optimise / refactor / performance"? | Functional equivalence must be verified — every path that worked before must still work |
124
+
125
+ ### ⚠️ RULE #2a — REUSED METHODS ARE A REGRESSION TRAP
126
+
127
+ When the diff *reuses* a shared method without modifying it, DO NOT conclude "conflict/filter/sort semantics behaviour is out of scope". A shared method invoked from a new caller sees a **new input surface**.
128
+
129
+ For every reused-but-unmodified method the endpoint calls:
130
+
131
+ 1. Read the method's signature and identify each input dimension it varies on (trigger types, filter operators, attribute types, engine, FF state, permission role, etc.).
132
+ 2. Enumerate the input dimensions the OLD caller fed it. This is your existing coverage baseline.
133
+ 3. Enumerate the input dimensions the NEW caller can feed it — this is usually broader (e.g. a bulk endpoint receives every combination the area holds; a single endpoint gets one row at a time).
134
+ 4. For every dimension in step 3 that isn't in step 2, add at least one positive test case that exercises the reused method with that input.
135
+
136
+ Document the dimension analysis in the Summary "Code Review" section as a small table:
137
+
138
+ ```
139
+ Reused method: findConflictsForRule
140
+ Input dimensions: [trigger type × trigger value × trigger-set count]
141
+ Old caller (single endpoint): one rule at a time — narrow
142
+ New caller (bulk endpoint): every rule in the area — broad
143
+ Combinations to cover: MATCHES↔MATCHES same value / MATCHES↔CONTAINS same value /
144
+ MATCHES↔MATCHES diff value / multi-trigger-set rule vs single-set rule
145
+ ```
146
+
147
+ "Not modified" ≠ "not exercised in a new way." Every dimension in step 3-minus-step-2 is a **behavioural** TC, not just a shape check.
148
+
149
+ ### Code vs. spec — use judgment
150
+
151
+ - The code tells you *what was built*; the ticket + comments tell you *what was requested*
152
+ - Usually when they diverge, the code has a bug — but the spec can also be wrong or incomplete
153
+ - Don't blindly trust either: read both, compare, and if they differ → flag it as a discrepancy for the user to clarify rather than silently picking one side
154
+ - Your test cases should reflect *what was requested* as the primary goal, but note where the code behaves differently
155
+
156
+ ### Translating code findings into test cases
157
+
158
+ - **Exact field names from new models/DTOs** → use verbatim in curl bodies and assertion keys
159
+ - **Exact error messages from exception throws** → use verbatim in Expected Result column
160
+ - **Every if/else branch in changed code** → each branch needs its own test case (positive or negative)
161
+ - **Every shared method that was modified** → add regression tests for ALL existing callers, not just the new one
162
+ - **Every shared method that was reused-but-unmodified** → run RULE #2a on it
163
+ - **"Optimise / performance" PR** → add a functional-equivalence set: same inputs as before, same outputs expected
164
+ - **Batch DB queries** → add a large-batch test to verify the query actually batches and doesn't N+1
165
+
166
+ ### Developer QA verification comments
167
+
168
+ Developer comments (e.g. from Haris, Andrii, or others) confirming implementation details are gold:
169
+ - Extract exact warning/error message strings and use them verbatim in Expected Result
170
+ - Extract exact log field names and use them in GCP Log Check
171
+ - Treat them as implementation evidence, not spec
172
+
173
+ ---
174
+
175
+ ## ⚠️ RULE #3 — AFTER TEST PLAN/CASES, ALWAYS OFFER POSTMAN FIRST
176
+
177
+ **User preference (Anzhelika, SNPD QA):** tests must live where they're fastest to run and easiest to maintain. That means Postman by default.
178
+
179
+ Every time you finish generating or updating a test plan or test cases (Excel), your very next message MUST offer to generate/update a Postman collection with `pm.test` assertions covering those cases — including when you add new TCs to an existing plan (offer to update the matching Postman collection for those TCs too). Do not wait to be asked. Do not offer pytest/GitHub Actions as the default.
180
+
181
+ Only fall back to pytest in `bs-qa-automation` (via `be-github-actions-qa` skill) when Postman genuinely cannot cover the case — e.g. multi-step data seeding that Postman scripting can't do cleanly, GCP log verification, DB query-count checks, cross-service orchestration, or scheduled CI runs. In those cases name the specific TC(s) that need pytest and keep the rest in Postman.
182
+
183
+ The offer wording should be short and concrete: name which TCs will get `pm.test` blocks, which collection file will be updated (or created), and which TC(s) — if any — need a manual/pytest fallback and why.
184
+
185
+ ---
186
+
187
+ ## ⚠️ RULE #4 — SELF-SEED TEST DATA. NEVER ASSUME IT EXISTS.
188
+
189
+ **User preference (Anzhelika, SNPD QA):** every Postman collection must prepare its own test data and clean it up afterwards. Do not write requests that depend on rules, attributes, areas, or products existing in the tenant "by convention".
190
+
191
+ **Every Postman collection this skill produces must have:**
192
+
193
+ 1. A `SETUP` folder that creates every entity the tests need via API — rules, folders, attributes, filter sets, whatever the endpoint under test operates on. The created IDs are stored to environment (or collection) variables that the test folders then reference.
194
+ 2. A `TEARDOWN` folder that deletes everything SETUP created (in reverse dependency order) and clears the transient variables. TEARDOWN must be idempotent — if a var is not set (SETUP was skipped or already cleaned), the request logs a message and moves on, it does not fail the run.
195
+ 3. Every SETUP body must use a shared `run_ts` (e.g. `Date.now()` stored in `pm.environment`) so re-runs never collide on unique names.
196
+ 4. If the create endpoint's body shape is not confirmed by an existing curl / working collection / code you just read, **STOP and ask for a working curl** (GOLDEN RULE + RULE #1b). Do not invent a `RuleModel`, `AttributeModel`, etc. from memory.
197
+ 5. If a working example already lives in another collection in `/Users/lika/Documents/Claude/Projects/Rezolve/` (e.g. `S4R-11059_BatchSizeTest_gbiqa-lo.postman_collection.json` has a full `POST /rule` body), copy that body verbatim as the seeding payload rather than composing a new one — but replace hardcoded bearer tokens with `Bearer {{bearer_token}}`.
198
+
199
+ **SETUP must seed every input combination RULE #2a identified.** If the reused-method analysis says the bulk endpoint sees CONTAINS↔CONTAINS, MATCHES↔MATCHES, MATCHES↔CONTAINS, and multi-trigger-set rules — SETUP must create at least one rule of each so the TCs have data to run against. A SETUP folder that only creates the minimum for the happy path is a coverage smell.
200
+
201
+ **Test folders may only reference entities that SETUP created** (`{{ruleIdA}}`, `{{ruleIdB}}`, etc.). If a TC genuinely needs an entity SETUP cannot produce (e.g. a specific role token, a deleted-then-restored record), leave a comment in the SETUP folder README naming the manual prerequisite — don't silently rely on it.
202
+
203
+ **Manual seeding is only acceptable when the API cannot create the entity** — e.g. tenants, LaunchDarkly flags, IAM roles. Say so explicitly in the SETUP README.
204
+
205
+ ---
206
+
207
+ ## ⚠️ RULE #5 — DELIVER A MANUAL CHECK GUIDE AFTER POSTMAN/GITHUB
208
+
209
+ **After sending the Postman collection (or the GitHub Actions / pytest deliverable), your next chat message MUST include a Manual Check Guide** — step-by-step instructions Anzhelika can follow by hand to verify the tests actually cover what they claim. Do not wait to be asked.
210
+
211
+ The Manual Check Guide must contain:
212
+
213
+ 1. **Environment setup** — which Postman env to select (`gbiqa-lo` / `gbiqa`), which variables must be filled in (bearer_token freshness, ccapi_customer_id), any LaunchDarkly flag state to confirm, tenant to be logged into.
214
+ 2. **Run order** — exact folder run sequence (usually `SETUP` → `[FF=ON] POSITIVE` → `[FF=OFF] REGRESSION` → `NEGATIVE` → `EDGE / REGRESSION` → `KNOWN-BUGS` → `TEARDOWN`) and whether to use Collection Runner or run folder-by-folder.
215
+ 3. **Per-TC manual verification steps** — for each meaningful TC (positive, semantic, known-bug, and any TC not fully assertable by `pm.test`), spell out: (a) what to run, (b) what to look at in the response, (c) what the correct value is, (d) what to check in Commerce Console UI or GCP logs if applicable. Use numbered steps, one action per line.
216
+ 4. **GCP log verification steps** — for any `[LOGGING]` TC: the exact GCP filter (`resource.type="k8s_container"` + `jsonPayload.message:"<id>"`), which project/cluster, what to look for (severity, message contents), how to correlate to the request's tracking id.
217
+ 5. **UI verification steps** (if applicable) — which Commerce Console page to open, what to click, what to confirm visually.
218
+ 6. **Cleanup confirmation** — how to verify TEARDOWN actually deleted everything (list check via GET, or "no leftover rules named `qa-{{run_ts}}-*`").
219
+ 7. **What "green" looks like** — the one-line success condition for the whole run ("all pm.tests pass, TEARDOWN reports 200/204 on every DELETE, no leftover entities in `Rules → All rules`").
220
+ 8. **What to do if a test fails** — one-liner reminder: "paste the failing pm.test output back — I'll invoke `failed-test-triage`."
221
+
222
+ **Format:** post the Manual Check Guide inline in chat as a numbered checklist under a clear heading (e.g. `### Manual Check Guide — <TICKET-KEY>`). Keep it copy-pasteable — she should be able to run through it without switching back to the Excel.
223
+
224
+ For pytest / GitHub Actions deliverables the Manual Check Guide adapts to: how to trigger the workflow (branch push / manual dispatch), which job to watch, how to read the logs, and how to correlate failures to TC numbers.
225
+
226
+ ---
227
+
228
+ ## Step 0a — Clarify scope
229
+
230
+ Ask the user:
231
+
232
+ > "Should I look at the parent Epic/Story this ticket is attached to as well?
233
+ > - **Yes** — I'll fetch the ticket + its parent Epic/Story + all related tickets (with their comments and statuses)
234
+ > - **No** — I'll look at this ticket only + its comments + directly linked (relates to) issues"
235
+
236
+ ## Step 0b — Check existing Qase coverage
237
+
238
+ Ask:
239
+
240
+ > "Does a Qase test suite already exist for this ticket?
241
+ > - **Yes** — I'll factor in existing cases and only generate new cases for gaps (tell me the suite title or case IDs)
242
+ > - **No / Not sure** — I'll generate full coverage from scratch"
243
+
244
+ If the user confirms existing coverage, reference existing Qase case IDs in the `Automation` column of the Excel (mark as `is-automated`) and skip duplicating those scenarios in new test cases.
245
+
246
+ ---
247
+
248
+ ## Step 0 — Create ticket folder in workspace
249
+
250
+ Before doing anything else, create a dedicated subfolder for this ticket inside the **Tasks** folder:
251
+
252
+ ```
253
+ /Users/lika/Documents/Claude/Projects/Rezolve/Tasks/<TICKET-KEY>/
254
+ ```
255
+
256
+ Save **all outputs** for this ticket into that folder:
257
+ - Excel test plan → `<TICKET-KEY>_Test_Plan.xlsx`
258
+ - Postman collection → `<TICKET-KEY>_Postman_Collection.json`
259
+ - Qase export → `<TICKET-KEY>_Qase_Export.csv`
260
+ - Bug reports and repro collections → use the `bug-report` skill (Step 6b)
261
+
262
+ **Versioning rule:** when a new version of a file is produced (e.g. after a dev fix), suffix it with `_v2`, `_v3`, etc. Move the previous version into an `outdated/` subfolder inside the ticket folder.
263
+
264
+ Never dump ticket files into the root of the workspace — always use `Tasks/<TICKET-KEY>/`.
265
+
266
+ ---
267
+
268
+ ## Area & Collection Reference (gbiqa-lower / gbiqa tenant)
269
+
270
+ **Always use these areas — do not ask the user to confirm unless the ticket explicitly involves a different tenant or environment.**
271
+
272
+ | Collection | Area | FF state | Use for |
273
+ |---|---|---|---|
274
+ | `productsClothing` | `regressionAutomation` | FF=ON | Non-inventory tests — positive, negative, edge, regression |
275
+ | `productsClothing` | `onehundredregression` | FF=OFF | Non-inventory FF=OFF regression |
276
+ | `tenaquip` | `tenaquip` | FF=ON | Inventory attribute tests — FF=ON |
277
+ | `tenaquip` | `regressionAutomationTenaquip` | FF=OFF | Inventory attribute tests — FF=OFF |
278
+
279
+ **Why this split:**
280
+ - `productsClothing` has **no inventory attributes** — all non-inventory attribute type tests run here
281
+ - `tenaquip` has **inventory attributes** (custom textual/numerical, system numerical) — mandatory for inventory test coverage
282
+ - LaunchDarkly flag targeting is **per-collection** (not tenant-wide)
283
+ - Always clean up after testing (reset attributes to original state).
284
+
285
+ ---
286
+
287
+ ## Confirmed test attributes (update as new ones are validated)
288
+
289
+ ### productsClothing attributes
290
+
291
+ | Attribute key | CCAPI path | Type | Group | Root-level? | Varied values | Use for |
292
+ |---|---|---|---|---|---|---|
293
+ | `attributes.discountPercentage` | `attributes.discountPercentage` | NUMERICAL | CUSTOM | ✅ Yes | 0, 25, 30, 50, 70% | Custom Numerical sort tests + ordering verification |
294
+ | `title` | `title` | TEXTUAL | SYSTEM | ✅ Yes | Always varied | System Textual sort tests + ordering verification |
295
+ | `attributes.category1` | `attributes.category1` | TEXTUAL | CUSTOM | ✅ Yes (confirmed) | Varied (AERIE, AMERICAN EAGLE, etc.) | Custom Textual sort tests |
296
+ | `price` | `priceInfo.price` | NUMERICAL | SYSTEM | ✅ Yes (root=239.25; variant L=599.25) | Varies | System Numerical sort. Request as `fields:["price"]` |
297
+
298
+ ### tenaquip attributes (inventory)
299
+
300
+ | Attribute key (CCAPI) | Sort syntax (SSA) | Type | Group | Use for |
301
+ |---|---|---|---|---|
302
+ | `inventories.attributes.gbi_on_sale` | `inventory(MTL, attributes.gbi_on_sale)` | TEXTUAL | INVENTORY CUSTOM | Inventory Custom Textual exclusion test. Value: "N" |
303
+ | `inventories.attributes.gbi_discount_percent` | `inventory(MTL, attributes.gbi_discount_percent)` | NUMERICAL | INVENTORY CUSTOM | Inventory Custom Numerical exclusion test |
304
+ | `inventories.price` | `inventory(MTL, price)` | NUMERICAL | INVENTORY SYSTEM | Inventory System Numerical sort. Values: 2376, 1326, etc. (cents) |
305
+
306
+ > **placeId for tenaquip = `MTL`**
307
+
308
+ > **Inventory System vs Custom:** SYSTEM = `inventories.price` (no `.attributes`); CUSTOM = `inventories.attributes.X`
309
+
310
+ > **To see inventory values in search response:** use `variantRollupKeys`, NOT `fields`. Values appear in `allMeta.variantRollUpValues`.
311
+
312
+ > **Inventory CCAPI query:** use `attributeGroup=INVENTORY` as top-level query param (NOT as a filter).
313
+
314
+ **Inventory System Textual** — SKIP. No clients have this.
315
+
316
+ ---
317
+
318
+ ## Postman environment variable names
319
+
320
+ | Variable | Usage |
321
+ |---|---|
322
+ | `{{clientKey}}` | client key for Search API auth |
323
+ | `{{bearer_token}}` | Bearer token for CCAPI auth (**NOT** `{{bearerToken}}`) |
324
+ | `{{x-groupby-customer-id}}` | customer/tenant ID header value |
325
+ | `{{search_url}}` | base Search URL |
326
+ | `{{cc_url}}` | base CCAPI URL |
327
+ | `{{ccapi_customer_id}}` | **Numeric ID in CCAPI URL path `/ccapi/{id}/`** (NOT `{{areaId}}`) |
328
+ | `{{collection}}` | collection name |
329
+ | `{{area}}` | area name |
330
+
331
+ **`{{areaId}}` does NOT exist in gbiqa-lo env** — use `{{ccapi_customer_id}}` for numeric CCAPI path IDs.
332
+
333
+ When generating Postman collections: read `/Users/lika/Documents/Claude/Projects/Rezolve/gbiqa-lo.postman_environment.json` first to confirm variable names. If a needed variable is missing from the env file, tell the user and ask them to add it manually.
334
+
335
+ ---
336
+
337
+ ## CCAPI PATCH body rules
338
+
339
+ **Full object required** — send the complete attribute object, not just changed fields.
340
+
341
+ **Always include:**
342
+ ```json
343
+ "lastModifiedField": "sortable",
344
+ "lastModifiedDate": <CURRENT_EPOCH_MS>
345
+ ```
346
+
347
+ Get epoch ms: `date +%s%3N` in bash, or `Date.now()` in JS.
348
+
349
+ ---
350
+
351
+ ## Step 1 — Fetch Ticket Data via Atlassian MCP
352
+
353
+ Fetch: main ticket (full description + all comments), parent/Epic (if scope=Yes), all linked issues (status + comments).
354
+
355
+ **Immediately after fetching**, extract the numeric issue `id` and run the dev-status API procedure from RULE #2 to find all PR URLs. Do this before Step 2.
356
+
357
+ ---
358
+
359
+ ## Step 1a — Classify EVERY linked issue (mandatory)
360
+
361
+ Linked issues are not context to skim — they are **test cases waiting to be written**. Fetch each linked issue's full description + comments (already done in Step 1), then classify:
362
+
363
+ | Bucket | Meaning | Action in this ticket's plan |
364
+ |---|---|---|
365
+ | **Blocker / prerequisite** | Linked issue must resolve before testing this one | Add to Open Questions; note in Excel Summary; do NOT proceed with dependent TCs until resolved |
366
+ | **Bug I (or QA) filed during this ticket's own QA** | The bug reproduces on the surface area *this* ticket added or touched | **Add a `[KNOWN-BUG]` pinned TC** that reproduces it and asserts *current* behaviour (buggy or correct). Include the linked issue key in the TC title. When the bug is fixed later, the assertion flips → free regression signal. This is mandatory regardless of the fix-scope decision on the linked bug. |
367
+ | **Related feature / follow-up** | Separate work that touches the same area but is not tested here | Reference in Summary "Related work"; no TC |
368
+ | **Duplicate** | Same defect / same feature | Ignore |
369
+
370
+ **Never treat a bug you filed during this ticket's QA as "out of scope" and stop there.** The reproduction always belongs in this ticket's test suite — because that is where the surface area was introduced or last modified. If the fix ships in a different ticket, the `[KNOWN-BUG]` TC in this suite is where you'll notice.
371
+
372
+ Document the classification in the Excel Summary sheet as a table.
373
+
374
+ ---
375
+
376
+ ## Step 2 — Read the Code (MANDATORY — see RULE #2)
377
+
378
+ Before analysing context or writing any test cases, complete the full code review from RULE #2 — including RULE #2a for every reused shared method.
379
+ Document findings (before/after, branches, side effects, new models, reused-method input-dimension table) in the Summary & Setup sheet.
380
+
381
+ ---
382
+
383
+ ## Step 2.5 — Post Open Questions in chat (RULE #1a)
384
+
385
+ After the code review, before generating the Excel: if there are ANY open questions, post them as a single numbered list in chat and wait. Do not start Step 5 until each is answered or explicitly skipped by the user.
386
+
387
+ ---
388
+
389
+ ## Step 3 — Understand the Full Context
390
+
391
+ 1. What is the actual change? (informed by code, not just ticket)
392
+ 2. What was the code doing before? What changed?
393
+ 3. Which system components are touched? What else uses the changed code?
394
+ 4. Which **search engines** are involved? (Google Search / Google Browse / Mongo Browse / Mongo+Google Fallback)
395
+ 5. Are **both filter sources** involved? (`preFilter` + `siteFilter`)
396
+ 6. Are **all attribute types** covered?
397
+ 7. Configurable thresholds, flags, vault settings?
398
+ 8. Explicit ACs? Implied behaviour? Code-implied behaviour not in spec?
399
+ 9. Every linked issue classified per Step 1a?
400
+
401
+ ### Step 3a — Configuration questions
402
+
403
+ Ask before writing tests if the ticket involves configurable flags, limits, timeouts, or vault settings. These go into the RULE #1a Open Questions batch.
404
+
405
+ ---
406
+
407
+ ## Step 4 — Identify Test Coverage Areas
408
+
409
+ Coverage tags:
410
+ - `[POSITIVE]` — happy path, expected behaviour
411
+ - `[NEGATIVE]` — error handling, invalid input
412
+ - `[EDGE]` — boundaries, empty/max sizes, unusual valid combinations
413
+ - `[REGRESSION]` — verifies existing callers of modified/reused methods still work
414
+ - `[CONFIG]` — feature-flag / threshold / vault-setting variations
415
+ - `[LOGGING]` — GCP log content, severity, count
416
+ - `[SCHEMA]` — response structure only
417
+ - `[SEMANTIC]` — response *content* is correct given the input
418
+ - `[KNOWN-BUG]` — pinned TC asserting current buggy behaviour of a linked open bug
419
+ - `[PERF]` — response time / batch efficiency / N+1 checks
420
+
421
+ Coverage must include every code branch found in the diff, every reused-method input dimension identified by RULE #2a, and one TC per linked-issue "known-bug-to-pin" from Step 1a.
422
+
423
+ ### ⚠️ RULE #4a — SCHEMA vs SEMANTIC for nested / aggregated responses
424
+
425
+ For any response with a nested or aggregated shape produce **two** TCs per feature: one `[SCHEMA]` and one `[SEMANTIC]`. Schema-only is a shape rubber-stamp; semantic is where the real bugs live.
426
+
427
+ ---
428
+
429
+ ## Step 5 — Write Test Cases (Excel output — MANDATORY)
430
+
431
+ **Precondition:** RULE #1a Open Questions batch resolved.
432
+
433
+ ### Step 5a — Summary table in chat
434
+
435
+ Post scope, engines covered, attribute types, FF/config state, PRs reviewed, code findings, reused-method dimensions, linked-issue classification, spec/code discrepancies.
436
+
437
+ ### Step 5b — Generate Excel
438
+
439
+ Two sheets: **Summary & Setup** + **Test Cases**. Standard columns (TC #, Priority, Engine/Service, FF State, Attribute Type, Collection/Area, Title, Preconditions, CURL full, Expected HTTP, Expected Result, GCP Log Check, Coverage Tag, Automation).
440
+
441
+ **CURL format — mandatory** with all headers and `{{placeholder}}` secrets.
442
+
443
+ **Section rows** (dark NAVY) + colour coding by tag and priority as before.
444
+
445
+ ---
446
+
447
+ ## Step 6 — Automation Assessment
448
+
449
+ ```
450
+ | TC | Automatable | Tool | Reason |
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Step 7 — Workflow after Excel approval
456
+
457
+ **Immediately after delivering the Excel** (per RULE #3), your very next message offers to build/update the Postman collection covering the new TCs. Do not wait for the user to ask.
458
+
459
+ ### 7a — Postman Collection (default automation target)
460
+
461
+ **⚠️ MANDATORY AUTO-INVOKE — DO THIS FIRST:** As soon as the user agrees to generate/update the Postman collection (or asks for `pm.test`, Newman, or any Postman-related work), you MUST invoke the `postman-qa` skill via the Skill tool BEFORE writing a single request or assertion. Do not compose Postman JSON from memory — load `postman-qa` first, then follow its rules. If the request touches Rezolve/GroupBy Search API, also invoke `rezolve-search-api` for reference.
462
+
463
+ **⚠️ RULE #1b PRECONDITION:** Before writing any request, ensure you have a working curl for every endpoint the collection will hit (endpoint under test + every SETUP create + every TEARDOWN delete). If not, ask the user in one numbered list and WAIT. Only exception: verbatim copy from an existing collection in `Tasks/`.
464
+
465
+ Before generating: **check if the user already has a Postman collection for this endpoint. If yes, ask for the file and add/fix requests there instead of generating from scratch.**
466
+
467
+ - Top-level description: ticket key, summary, link, plain-English feature explanation, PR reviewed, list of entities SETUP seeds, and any `[KNOWN-BUG]` TCs with their linked bug keys
468
+ - **Folders (mandatory in this order):** `SETUP` → `[FF=ON] POSITIVE` → `[FF=OFF] REGRESSION` → `NEGATIVE` → `EDGE / REGRESSION` → `KNOWN-BUGS` → `TEARDOWN`
469
+ - Auth: `{{bearer_token}}` for CCAPI
470
+ - GCP helper in every test: `console.log('GCP: jsonPayload.message:"' + (pm.response.json()?.id || '') + '"')`
471
+ - Include `lastModifiedField` + `lastModifiedDate` in all CCAPI PATCH requests
472
+ - **Base assertions on actual code**: use exact field names from models, exact error strings from exceptions
473
+ - **URL format**: use plain string `"url": "{{cc_url}}/..."` — NOT `{"raw": "..."}` without protocol/host/path
474
+ - **Integer fields**: `[{{ruleId}}]` not `["{{ruleId}}"]`
475
+ - **`[KNOWN-BUG]` TCs**: pm.test names must include the linked bug key.
476
+
477
+ ### 7a-self-seeding — RULE #4 in practice
478
+
479
+ Every Postman collection: SETUP folder (one item per seeded entity, seed every RULE #2a dimension) → test folders reference `{{varName}}` only → TEARDOWN folder (idempotent DELETE per seeded entity, reverse order) + reusable payload from `Tasks/S4R-11059/...`.
480
+
481
+ ### 7a-fallback — pytest via be-github-actions-qa (only when Postman can't cover)
482
+
483
+ **⚠️ MANDATORY AUTO-INVOKE — DO THIS FIRST:** As soon as the user agrees to any pytest / GitHub Actions work (or you decide a TC needs the pytest fallback), you MUST invoke the `be-github-actions-qa` skill via the Skill tool BEFORE writing any pytest code, conftest changes, or workflow YAML. Do not compose from memory.
484
+
485
+ Offer pytest ONLY for TCs Postman cannot reasonably automate. Name the specific TC(s) and reason.
486
+
487
+ ### 7b — Deliver the Manual Check Guide (RULE #5)
488
+
489
+ Immediately after sending the Postman collection (or the pytest / GitHub Actions deliverable), post the Manual Check Guide in chat per RULE #5. Do not wait to be asked. Cover env setup, run order, per-TC verification steps, GCP log steps, UI steps, cleanup confirmation, definition of "green", and failure handoff to `failed-test-triage`.
490
+
491
+ ### 7c — Bug reports via `bug-report` skill
492
+
493
+ When testing surfaces a product defect the user wants to file, invoke the `bug-report` skill via the Skill tool before drafting the report.
494
+
495
+ ---
496
+
497
+ ## Step 7.5 — When tests are run and any fail: auto-invoke failed-test-triage
498
+
499
+ **⚠️ MANDATORY AUTO-INVOKE:** The moment the user comes back with failing test output — Newman/Postman failures, GitHub Actions red job, pasted pytest AssertionError, screenshots of red runs, "why did this fail", "is this a bug or a test issue" — you MUST invoke the `failed-test-triage` skill via the Skill tool BEFORE analysing the failure. Do not diagnose from memory. This applies whether the tests came from Postman (7a) or pytest (7a-fallback).
500
+
501
+ If triage concludes the failure is a real product bug, hand off to the `bug-report` skill (7c).
502
+
503
+ ---
504
+
505
+ ## Step 8 — Qase Export (only after testing complete)
506
+
507
+ Only after the user has run the tests and testing is confirmed complete, produce a Qase v2 CSV that imports cleanly into Qase's project — matching Qase's native export format exactly. An invalid file gets rejected outright ("Data is invalid", "not valid JSON", etc.), so the format below is not optional.
508
+
509
+ ### Qase v2 CSV — column layout (26 columns, exact order)
510
+
511
+ ```
512
+ v2.id, title, description, preconditions, postconditions, tags,
513
+ priority, severity, type, behavior, automation, status, is_flaky, layer,
514
+ steps_type, steps_actions, steps_result, steps_data,
515
+ milestone_id, milestone, suite_id, suite_parent_id, suite, suite_without_cases,
516
+ parameters, is_muted
517
+ ```
518
+
519
+ Column headers are lowercase and use `snake_case`. Any deviation (`Title` instead of `title`, `Step 1 Action` columns, etc.) fails import.
520
+
521
+ ### Allowed enum values (lowercase)
522
+
523
+ | Column | Allowed values |
524
+ |---|---|
525
+ | `priority` | `undefined`, `low`, `medium`, `high` |
526
+ | `severity` | `undefined`, `blocker`, `critical`, `major`, `normal`, `minor`, `trivial` |
527
+ | `type` | `functional`, `regression`, `smoke`, `security`, `usability`, `performance`, `acceptance`, `compatibility`, `integration`, `other` |
528
+ | `behavior` | `positive`, `negative`, `destructive` |
529
+ | `automation` | `is-not-automated`, `to-be-automated`, `automated` |
530
+ | `status` | `actual`, `draft`, `deprecated` |
531
+ | `is_flaky` | `no`, `yes` |
532
+ | `layer` | `api`, `e2e`, `unit` |
533
+ | `steps_type` | `classic`, `gherkin` |
534
+
535
+ Set `is_muted` to `no` on case rows.
536
+
537
+ ### Step columns — JSON-encoded string per step
538
+
539
+ `steps_actions`, `steps_result`, and `steps_data` each hold a SINGLE cell containing all steps of that type as numbered lines. Each step text must be a **valid JSON string literal** (Qase's importer parses each step as JSON):
540
+
541
+ ```
542
+ 1. "First action text"
543
+ 2. "Second action — with \"embedded quotes\" properly escaped"
544
+ 3. "Third"
545
+ ```
546
+
547
+ Build these using `json.dumps(text)` — never hand-format. Common failures:
548
+ - `\'` (backslash-apostrophe) — not valid JSON; use plain apostrophes and let `json.dumps` escape.
549
+ - Unescaped double quotes inside the step text — breaks the JSON literal.
550
+ - Missing wrapping quotes — the whole step-text MUST be quoted.
551
+
552
+ `steps_data` uses the same shape; put `""` for empty data slots so the numbering matches.
553
+
554
+ ### Suite structure
555
+
556
+ Two-row minimum for a fresh import:
557
+
558
+ 1. **Suite header row** — only these fields populated:
559
+ - `suite_id` (any integer you invent, e.g. `100`)
560
+ - `suite_parent_id` (blank for a top-level suite, or the id of a parent suite row)
561
+ - `suite` (display name, e.g. `S4R-11240 Sort by Primary Product Field`)
562
+ - `suite_without_cases` = `1`
563
+ 2. **Case rows** — every case row references the same `suite_id` and repeats the `suite` display name. `suite_without_cases` blank on case rows. `v2.id` blank on new cases.
564
+
565
+ Nested suites: add more header rows with their own `suite_id` and a `suite_parent_id` pointing at a previous header's `suite_id`.
566
+
567
+ ### Building the file (recipe)
568
+
569
+ ```python
570
+ import csv, json
571
+
572
+ HEADERS = [
573
+ "v2.id","title","description","preconditions","postconditions","tags",
574
+ "priority","severity","type","behavior","automation","status","is_flaky","layer",
575
+ "steps_type","steps_actions","steps_result","steps_data",
576
+ "milestone_id","milestone","suite_id","suite_parent_id","suite","suite_without_cases",
577
+ "parameters","is_muted",
578
+ ]
579
+
580
+ def steps_field(items):
581
+ if not items: return ""
582
+ return "".join(f'{i}. {json.dumps(s, ensure_ascii=False)}\n'
583
+ for i, s in enumerate(items, start=1))
584
+
585
+ def case_row(title, description, preconditions, actions, results, data=None,
586
+ suite_id="100", suite="<TICKET> Suite Name",
587
+ priority="undefined", severity="normal", type_="functional",
588
+ behavior="positive", automation="automated", tags=""):
589
+ data = data or ["" for _ in actions]
590
+ return {
591
+ "v2.id":"", "title":title, "description":description,
592
+ "preconditions":preconditions, "postconditions":"", "tags":tags,
593
+ "priority":priority, "severity":severity, "type":type_,
594
+ "behavior":behavior, "automation":automation, "status":"actual",
595
+ "is_flaky":"no", "layer":"api", "steps_type":"classic",
596
+ "steps_actions":steps_field(actions),
597
+ "steps_result": steps_field(results),
598
+ "steps_data": steps_field(data),
599
+ "milestone_id":"", "milestone":"",
600
+ "suite_id":suite_id, "suite_parent_id":"", "suite":suite,
601
+ "suite_without_cases":"", "parameters":"", "is_muted":"no",
602
+ }
603
+
604
+ with open("<TICKET>_Qase_Export.csv","w",newline="") as f:
605
+ w = csv.DictWriter(f, fieldnames=HEADERS)
606
+ w.writeheader()
607
+ header = {h:"" for h in HEADERS}
608
+ header["suite_id"]="100"; header["suite"]="<TICKET> Suite Name"
609
+ header["suite_without_cases"]="1"
610
+ w.writerow(header)
611
+ for row in rows: w.writerow(row)
612
+ ```
613
+
614
+ ### Sanity-check the file BEFORE presenting
615
+
616
+ Programmatically verify every step value parses as JSON — catches the most common failure that Qase rejects with a cryptic error:
617
+
618
+ ```python
619
+ import csv, json
620
+ with open(path) as f:
621
+ for i, row in enumerate(csv.DictReader(f)):
622
+ for col in ("steps_actions","steps_result","steps_data"):
623
+ for line in (row[col] or "").splitlines():
624
+ if not line.strip(): continue
625
+ payload = line[line.find(". ")+2:]
626
+ json.loads(payload) # raises if invalid
627
+ ```
628
+
629
+ Save the file to `Tasks/<TICKET-KEY>/<TICKET-KEY>_Qase_Export.csv`. Present it. Tell the user to import via Qase → Test Cases → Import → CSV.
630
+
631
+ ---
632
+
633
+ ## Workflow Summary
634
+
635
+ ```
636
+ Ask ALL scope/Qase clarifying questions (ONE message)
637
+
638
+ Create Tasks/<TICKET-KEY>/ folder
639
+
640
+ Fetch Jira: ticket + parent + linked issues + all comments
641
+
642
+ Step 1a — Classify every linked issue
643
+
644
+ Get numeric issue ID → call dev-status API → get PR URL(s)
645
+
646
+ Navigate to PR /files tab in browser → read full diff → RULE #2a per reused method
647
+
648
+ Step 2.5 — RULE #1a: post ALL Open Questions in chat → WAIT for answers
649
+
650
+ Post summary table → generate Excel
651
+
652
+ IMMEDIATELY offer Postman collection (RULE #3)
653
+
654
+ User approves Postman → RULE #1b: ask for any missing working curls → WAIT
655
+
656
+ INVOKE `postman-qa` skill (mandatory) → build with SETUP + TEARDOWN + REGRESSION + KNOWN-BUGS
657
+
658
+ Deliver the collection → RULE #5: post Manual Check Guide in chat (mandatory)
659
+
660
+ (If pytest fallback needed → INVOKE `be-github-actions-qa` → also deliver Manual Check Guide)
661
+
662
+ User runs tests and reports failures → INVOKE `failed-test-triage` skill (mandatory)
663
+
664
+ If real bug found → INVOKE `bug-report` skill
665
+
666
+ Testing complete → Qase export (v2 CSV per Step 8 above)
667
+ ```
668
+
669
+ ---
670
+
671
+ ## QA Mindset Checklist
672
+
673
+ - [ ] Did I ask ALL scope/Qase clarifying questions BEFORE fetching anything?
674
+ - [ ] **RULE #1a: did I post ALL Open Questions in chat and WAIT for answers before generating the Excel?**
675
+ - [ ] **RULE #1b: before writing any Postman request, did I confirm I have a working curl for every endpoint (or explicitly reuse one from `Tasks/`)?**
676
+ - [ ] Did I read the env file before writing any Postman variable names?
677
+ - [ ] Did I use `{{ccapi_customer_id}}` (not `{{areaId}}`) for numeric CCAPI path IDs?
678
+ - [ ] Did I use plain string `"url"` format (not `{"raw": "..."}`) in Postman JSON?
679
+ - [ ] Are Integer fields unquoted in Postman body: `[{{id}}]` not `["{{id}}"]`?
680
+ - [ ] Did I call the dev-status API to get the PR URL(s)?
681
+ - [ ] Did I navigate to the PR /files tab and read the full diff?
682
+ - [ ] If SSO blocked access, did I ask the user to log in and wait before proceeding?
683
+ - [ ] Did I document what the code did BEFORE and what it does NOW?
684
+ - [ ] Did I identify ALL code branches and create test cases for each?
685
+ - [ ] Did I identify all shared/reused methods that were changed and expand regression scope?
686
+ - [ ] **Did I identify every REUSED-but-unmodified method and run RULE #2a input-dimension analysis?**
687
+ - [ ] **Does SETUP seed every RULE #2a dimension, not just the happy path?**
688
+ - [ ] Did I read ALL developer QA verification comments and extract exact formats/values?
689
+ - [ ] Did I compare code vs ticket spec and flag any discrepancies?
690
+ - [ ] **Did I classify EVERY linked issue per Step 1a?**
691
+ - [ ] **For every bug I (or QA) filed during this ticket's QA: did I add a `[KNOWN-BUG]` pinned TC?**
692
+ - [ ] Does every AC have at least one test case?
693
+ - [ ] Does every code branch have at least one test case?
694
+ - [ ] **For every nested / aggregated response: did I write both a `[SCHEMA]` TC and a `[SEMANTIC]` TC (RULE #4a)?**
695
+ - [ ] Are ALL four engines covered where applicable?
696
+ - [ ] Are ALL attribute types covered?
697
+ - [ ] Did I use correct area/collection pairs?
698
+ - [ ] Is there at least one negative test for every main flow?
699
+ - [ ] Did I check boundary values on numeric inputs?
700
+ - [ ] Did I check logging severity, count, and exact format?
701
+ - [ ] Is there a regression guard for all existing callers of modified shared methods?
702
+ - [ ] FF=ON AND FF=OFF with correct area pairs?
703
+ - [ ] Are ALL curls in full format with all headers and `{{placeholder}}` secrets?
704
+ - [ ] `{{bearer_token}}` (NOT `{{bearerToken}}`) for CCAPI?
705
+ - [ ] CCAPI PATCH bodies include `lastModifiedField` + `lastModifiedDate`?
706
+ - [ ] `variantRollupKeys` (not `fields`) for inventory attribute values in search?
707
+ - [ ] GCP Log Check uses `id` from response body as trackingId?
708
+ - [ ] **Before writing any Postman: did I invoke the `postman-qa` skill?**
709
+ - [ ] **Before writing any pytest / GitHub Actions: did I invoke the `be-github-actions-qa` skill?**
710
+ - [ ] **When failures were reported: did I invoke the `failed-test-triage` skill before analysing?**
711
+ - [ ] **When a product bug needs filing: did I invoke the `bug-report` skill?**
712
+ - [ ] Does the Postman collection have SETUP + TEARDOWN + KNOWN-BUGS (if applicable)?
713
+ - [ ] **RULE #5: after delivering the Postman/GitHub collection, did I post the Manual Check Guide in chat (env, run order, per-TC steps, GCP steps, UI steps, cleanup, definition of green, failure-handoff line)?**
714
+ - [ ] All output files in Tasks/<TICKET-KEY>/?
715
+ - [ ] Qase export ONLY after testing is confirmed complete?
716
+ - [ ] **Qase v2 CSV per Step 8 format: 26 lowercase snake_case columns, `json.dumps`-encoded step text, suite header row + case rows, JSON-sanity-checked before presenting?**
717
+ - [ ] After delivering Excel, did I IMMEDIATELY offer a Postman collection (RULE #3)?
718
+ - [ ] Did I use pytest/GitHub Actions ONLY as a fallback for TCs Postman can't cover?
719
+