Przejdź do treści
Biblioteka skilli
Programowanie · Testowanie

wicked-garden-qe-incident-to-scenario-synthesizer

/wicked-garden-qe-incident-to-scenario-synthesizer

Zamienia incydent produkcyjny w deterministyczny scenariusz, który go odtwarza, z powiązaniem z raportem incydentu.

Repozytorium
wicked-garden ↗
Licencja
MIT
Ostatnia zmiana repozytorium
26.10.2026

Ocena i bezpieczeństwo

95/ 100Klasa: dobry
Format20 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
1
Skrypty
0
Komentarze HTML
1
Adresy URL w SKILL.md
0
Przestarzałość

Brak sygnałów. Repozytorium zmienione 26.10.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co sprawdzić przed instalacją
  • SKILL.md zawiera komentarze HTML (1). Nie widać ich w podglądzie Markdown, a model je czyta.

Co robi i kiedy

Zamienia incydent produkcyjny w deterministyczny scenariusz, który go odtwarza, z powiązaniem z raportem incydentu.

Wyzwalacze z opisu

write a regression test for INC-123
Oryginalny opis (EN)

Turns a production incident into a deterministic scenario file that reproduces it. Takes an incident-report markdown OR direct fields (stack trace, endpoint URL, HTTP method, request body), extracts the minimal reproducer, writes `scenarios/<incident-id>.md` with `linked_to_incident:` frontmatter, emits `wicked.qe.scenario.authored` with `source: incident`, and queues a review task under `assignee_skill: incident-to-scenario-synthesizer:review` so a human confirms before the scenario is marked active. Use when: postmortem follow-up, "write a regression test for INC-123", prod incident → scenar

Jak działa

  1. Runtime
  2. 1. Inputs
  3. 2. Extraction pipeline
  4. 3. Scenario synthesis
  5. 4. Evidence output
  6. 5. DomainStore + event bus
  7. 6. Failure modes
  8. 7. Non-negotiable rules
  9. 8. Output
  10. Helper resolution ({WTLIB})
Sekcje z nagłówków SKILL.md, w oryginale · 266 linii, 1 165 słów
Podgląd SKILL.md
---
name: wicked-garden-qe-incident-to-scenario-synthesizer
description: |
  Turns a production incident into a deterministic scenario file that
  reproduces it. Takes an incident-report markdown OR direct fields
  (stack trace, endpoint URL, HTTP method, request body), extracts the
  minimal reproducer, writes `scenarios/<incident-id>.md` with
  `linked_to_incident:` frontmatter, emits `wicked.qe.scenario.authored`
  with `source: incident`, and queues a review task under
  `assignee_skill: incident-to-scenario-synthesizer:review` so a human
  confirms before the scenario is marked active.

  Use when: postmortem follow-up, "write a regression test for INC-123",
  prod incident → scenario backport, error-class-to-test synthesis.
metadata:
  role: worker
---

# Incident-to-Scenario Synthesizer

A prod incident is a free test case — nature already generated the input.
You extract it and lock it down as a reproducible scenario. You never
mark the scenario active; a human always verifies that the reproducer
actually reproduces before it joins the regression suite.

## Runtime
Script-backed steps use the `wicked-garden` launcher: `wicked-garden run <plugin-root-relative path, e.g. scripts/…> [args]`. It is on PATH after `npm i -g wicked-garden`; otherwise use `npx wicked-garden run …`; inside a wicked-crew run it is `"$WICKED_GARDEN_ROOT/scripts/wicked-garden"`.
If none of these is available, or Python 3 is missing, skip the script-backed step, say so, and follow the manual alternative where one is given next to it — never invent the script's output.
Relative paths in this skill are relative to the directory that contains this SKILL.md.

## 1. Inputs

Accept either path A (incident report) OR path B (direct fields). Reject
if neither is provided.

### Path A — incident-report markdown

```yaml
# input
incident_report: docs/postmortems/INC-4829.md
incident_id: INC-4829        # optional; inferred from filename if omitted
```

The report is expected to contain, at minimum:
- A stack trace (fenced code block tagged `stack` or `traceback`).
- An HTTP request or curl example (fenced block tagged `http` or `curl`).
- An "affected endpoint" line matching `^(endpoint|route|path):`.
- An error class line: `error: <Exception or message>`.

### Path B — direct fields

```yaml
# input
incident_id: INC-4829
stack_trace: |
  TypeError: Cannot read property 'amount' of undefined
      at applyCoupon (/app/src/pricing/coupon.ts:42:15)
      at Checkout.finalize (/app/src/checkout.ts:188:7)
endpoint: POST /api/checkout
request_body: { "cart_id": "c_abc", "coupon": "SAVE10" }
expected_error_class: TypeError
```

- **`run_id`** — UUID of the current `runs` row; defines `EVIDENCE_DIR`.
- **`.wicked-qe/config.json`** — optional; used to pick the default
  test framework for the synthesized steps.
- **Scenario output dir** — `scenarios/`. Must exist. One file per
  incident id.

## 2. Extraction pipeline

```bash
# Path A: parse the markdown with a deterministic extractor that pulls
# the four required fenced/labelled blocks. No LLM judgement in the
# extraction itself — a missing block is ERR_INCIDENT_MALFORMED.
node {WT_LIB}/incident/extract.mjs \
  --report "${INCIDENT_REPORT}" \
  --out "${EVIDENCE_DIR}/extracted.json"

# Path B: normalize the inputs into the same extracted.json shape.
node {WT_LIB}/incident/normalize-direct.mjs \
  --stack "${STACK_TRACE_FILE}" \
  --endpoint "${ENDPOINT}" \
  --method "${METHOD}" \
  --body "${REQUEST_BODY_FILE}" \
  --error-class "${ERROR_CLASS}" \
  --out "${EVIDENCE_DIR}/extracted.json"
```

`extracted.json` shape:

```jsonc
{
  "incident_id": "INC-4829",
  "endpoint": { "method": "POST", "path": "/api/checkout" },
  "request_body": { /* parsed JSON or raw string */ },
  "expected_error_class": "TypeError",
  "stack_summary": {
    "top_frame_file": "src/pricing/coupon.ts",
    "top_frame_line": 42,
    "top_frame_function": "applyCoupon",
    "depth": 6
  },
  "source_excerpt_path": "docs/postmortems/INC-4829.md"
}
```

## 3. Scenario synthesis

Write exactly one file: `scenarios/<incident_id>.md`. Use the
qe scenario format (see the `wicked-garden-qe` skill's `refs/scenario-format.md`).

```markdown
---
name: Regression — INC-4829 coupon-reuse 500
status: pending-review
source: incident
linked_to_incident: INC-4829
authored_by: wicked-garden-qe-incident-to-scenario-synthesizer
authored_at: 2026-04-21T14:02:11Z
target: POST /api/checkout
trust_level: sandbox
tools:
  required: [curl, jq]
expected_error_class: TypeError
---

## Steps

1. POST to /api/checkout with the reproducer body below.
2. Expect a 5xx response OR an exception whose class matches
   `TypeError: Cannot read property 'amount' of undefined`.
3. Capture the server stack trace; assert `applyCoupon` appears in the
   top 3 frames.

## Reproducer

```bash
curl -sS -X POST "${TARGET_HOST}/api/checkout" \
  -H "content-type: application/json" \
  -d '{"cart_id":"c_abc","coupon":"SAVE10"}' \
  -w '\n%{http_code}\n' \
  > "${EVIDENCE_DIR}/response.txt"
```

## Evidence expected

- `response.txt` — HTTP response body + status code.
- `server-trace.txt` — captured exception trace (from log shipper).
- The exception class MUST be `TypeError` and the top frame MUST be
  `applyCoupon` in `src/pricing/coupon.ts`.

## Source

Synthesized from docs/postmortems/INC-4829.md by
`wicked-garden-qe-incident-to-scenario-synthesizer`.
Human review required — scenario is `pending-review` until approved.
```

## 4. Evidence output

Under `.wicked-qe/evidence/<run_id>/`:

| File                              | manifest `kind` | Required |
|-----------------------------------|-----------------|----------|
| `extracted.json`                  | `misc`          | Yes      |
| `synthesized-scenario-path.txt`   | `log`           | Yes      |
| `source-excerpt.md`               | `log`           | Yes (copy of the incident report) |
| `synthesis-log.md`                | `log`           | Yes      |

`synthesized-scenario-path.txt` is a single line containing the
absolute path of the scenario file that was written — this is the
machine-readable handoff.

`synthesis-log.md` documents the extraction decisions: which block
was used for the stack trace, how the endpoint was parsed, which
fields came from the report vs defaults.

## 5. DomainStore + event bus

```js
// 1. Verdict — always PASS for authoring; verdict is "scenario authored".
//    A FAIL here means extraction failed, not that the incident recurred.
store.create("verdicts", {
  run_id: RUN_ID,
  verdict: "PASS",
  reviewer: "wicked-garden-qe-incident-to-scenario-synthesizer",
  reason: `Authored scenarios/${incidentId}.md (pending-review) from ${sourcePath}.`,
  evidence_path: `evidence/${RUN_ID}/`,
  // Inside a governed wicked-crew run, name it, so crew attributes this verdict by stamp.
  ...(process.env.WICKED_RUN_ID ? { crew_run_id: process.env.WICKED_RUN_ID } : {}),
});

// 2. Task — human review is mandatory before the scenario goes active.
store.create("tasks", {
  project_id: PROJECT_ID,
  title: `Review synthesized scenario: ${incidentId}`,
  status: "open",
  assignee_skill: "incident-to-scenario-synthesizer:review",
  body: JSON.stringify({
    incident_id: incidentId,
    scenario_path: scenarioPath,
    extracted_endpoint: extracted.endpoint,
    expected_error_class: extracted.expected_error_class,
    top_frame: extracted.stack_summary,
    action_on_approve: "set status: active in scenario frontmatter",
  }),
});

// 3. Bus event so downstream listeners (e.g. a reviewer dashboard) can
//    surface the authored scenario immediately.
bus.emit("wicked.qe.scenario.authored", {
  scenario_path: scenarioPath,
  incident_id: incidentId,
  source: "incident",
  status: "pending-review",
  run_id: RUN_ID,
});
```

## 6. Failure modes

| code                          | meaning                                             | class  |
|-------------------------------|-----------------------------------------------------|--------|
| `ERR_NO_INPUT`                | neither incident_report nor direct fields provided  | user   |
| `ERR_INCIDENT_MALFORMED`      | report missing one of stack / endpoint / error class| user   |
| `ERR_SCENARIO_EXISTS`         | scenarios/<incident_id>.md already exists           | user   |
| `ERR_UNSAFE_ENDPOINT`         | endpoint path matches a deny-list (prod-only URL)   | user   |
| `ERR_INCIDENT_ID_MISSING`     | cannot infer incident_id from filename or inputs    | user   |
| `ERR_SCENARIO_WRITE_FAILED`   | filesystem write to scenarios/ failed               | system |

On `ERR_SCENARIO_EXISTS`: do NOT overwrite. Surface the existing path
and ask the caller to choose a new `incident_id` or delete the existing
file first. A scenario overwrite is a human decision.

## 7. Non-negotiable rules

- **`status: pending-review` is the only valid status on synthesis.**
  Never mark a synthesized scenario `active`. A human confirms it
  actually reproduces, then flips the status.
- **`linked_to_incident:` is required frontmatter.** Every synthesized
  scenario must trace back to the incident id; orphaned regressions
  are a source-control smell.
- **No destructive scenario steps.** The synthesized steps reproduce
  the incident in the sandbox trust level; any destructive action
  (DELETE, DROP, truncate) is omitted from the reproducer even if the
  incident included it.
- **Reproducer is copy-pasteable.** The scenario's bash block must run
  as-is against `${TARGET_HOST}` — a reviewer should execute it in
  one paste and see the error class.
- **Evidence expectations are explicit.** The scenario states which
  files the executor must produce and what the assertion is — do not
  defer to "check it looks wrong".

## 8. Output

```
## Incident-to-Scenario: {incident_id}
source: {incident_report | direct-fields}
endpoint: {method} {path}
expected_error_class: {class}
top_frame: {file}:{line} ({function})

synthesized: scenarios/{incident_id}.md   status: pending-review

emitted event: wicked.qe.scenario.authored  source=incident  run_id={RUN_ID}
queued task:   incident-to-scenario-synthesizer:review  ({incident_id})

VERDICT: PASS
REVIEWER: wicked-garden-qe-incident-to-scenario-synthesizer
RUN_ID: {RUN_ID}
```

## Helper resolution (`{WT_LIB}`)

`{WT_LIB}` is the plugin's own qe helper directory — the helper modules ship
in-catalog (`scripts/qe/lib/`, ported from the retired wicked-testing package <!-- historical -->
in Phase 6c). Resolve it (cross-platform):

```bash
WT_LIB="$(wicked-garden path scripts/qe/lib)"
```

Wersje

W bazie nie ma innych skilli o nazwie wicked-garden-qe-incident-to-scenario-synthesizer.

Migawka bazy z 28.10.2026 · wersja paczki 170867f770c2 (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 95wicked-garden-qe-scenario-executor
    Wykonuje pliki scenariuszy QE od początku do końca, uruchamia kroki w Bash i zapisuje dowody w formacie JSON.
  • 95wicked-garden-qe-acceptance-test-writer
    Pisze plany testów akceptacyjnych na podstawie scenariuszy, zamieniając kryteria jakościowe na weryfikowalne artefakty.
  • 100build-scenario-tests
    Zamienia scenariusz zachowania w Markdown w deterministyczny test w natywnym stosie testowym nieznanego repozytorium, uruchamia go i zachowuje powiązanie między intencją a kodem, także dla Given/When/Then.
  • 100add-scenario
    Dodaje scenariusz (animowany przepływ) do mapy Cosmos: śledzi rzeczywisty przepływ między repozytoriami i zapisuje wpisy Scenario i Step w src/scenarios.
  • 100incident-response
    Prowadzi ustrukturyzowaną reakcję na incydent produkcyjny, od zgłoszenia awarii i P0 po rolę incident commandera i koordynację odpowiedzi.
  • 100incident-postmortem-template
    Prowadzi pracę z szablonem postmortemu incydentu w ramach dokumentacji technicznej.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.