@brunosps00/dev-workflow 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +18 -14
  2. package/bin/dev-workflow.js +1 -1
  3. package/lib/constants.js +8 -2
  4. package/lib/init.js +6 -0
  5. package/lib/install-deps.js +0 -5
  6. package/lib/migrate-gsd.js +164 -0
  7. package/lib/uninstall.js +2 -2
  8. package/package.json +1 -1
  9. package/scaffold/en/commands/dw-analyze-project.md +6 -11
  10. package/scaffold/en/commands/dw-autopilot.md +6 -13
  11. package/scaffold/en/commands/dw-brainstorm.md +1 -1
  12. package/scaffold/en/commands/dw-code-review.md +6 -5
  13. package/scaffold/en/commands/dw-create-prd.md +5 -4
  14. package/scaffold/en/commands/dw-create-techspec.md +5 -4
  15. package/scaffold/en/commands/dw-execute-phase.md +149 -0
  16. package/scaffold/en/commands/dw-fix-qa.md +34 -13
  17. package/scaffold/en/commands/dw-help.md +5 -2
  18. package/scaffold/en/commands/dw-intel.md +98 -29
  19. package/scaffold/en/commands/dw-map-codebase.md +125 -0
  20. package/scaffold/en/commands/dw-new-project.md +1 -1
  21. package/scaffold/en/commands/dw-plan-checker.md +144 -0
  22. package/scaffold/en/commands/dw-quick.md +30 -12
  23. package/scaffold/en/commands/dw-redesign-ui.md +5 -9
  24. package/scaffold/en/commands/dw-refactoring-analysis.md +6 -5
  25. package/scaffold/en/commands/dw-resume.md +10 -8
  26. package/scaffold/en/commands/dw-run-plan.md +14 -20
  27. package/scaffold/en/commands/dw-run-qa.md +124 -23
  28. package/scaffold/en/commands/dw-run-task.md +5 -4
  29. package/scaffold/en/commands/dw-update.md +3 -1
  30. package/scaffold/en/templates/idea-onepager.md +1 -1
  31. package/scaffold/pt-br/commands/dw-analyze-project.md +6 -11
  32. package/scaffold/pt-br/commands/dw-autopilot.md +6 -13
  33. package/scaffold/pt-br/commands/dw-brainstorm.md +1 -1
  34. package/scaffold/pt-br/commands/dw-code-review.md +6 -5
  35. package/scaffold/pt-br/commands/dw-create-prd.md +5 -4
  36. package/scaffold/pt-br/commands/dw-create-techspec.md +5 -4
  37. package/scaffold/pt-br/commands/dw-execute-phase.md +149 -0
  38. package/scaffold/pt-br/commands/dw-fix-qa.md +34 -13
  39. package/scaffold/pt-br/commands/dw-help.md +5 -2
  40. package/scaffold/pt-br/commands/dw-intel.md +98 -29
  41. package/scaffold/pt-br/commands/dw-map-codebase.md +125 -0
  42. package/scaffold/pt-br/commands/dw-new-project.md +1 -1
  43. package/scaffold/pt-br/commands/dw-plan-checker.md +144 -0
  44. package/scaffold/pt-br/commands/dw-quick.md +30 -12
  45. package/scaffold/pt-br/commands/dw-redesign-ui.md +5 -9
  46. package/scaffold/pt-br/commands/dw-refactoring-analysis.md +6 -5
  47. package/scaffold/pt-br/commands/dw-resume.md +10 -8
  48. package/scaffold/pt-br/commands/dw-run-plan.md +16 -22
  49. package/scaffold/pt-br/commands/dw-run-qa.md +124 -23
  50. package/scaffold/pt-br/commands/dw-run-task.md +5 -4
  51. package/scaffold/pt-br/commands/dw-update.md +3 -1
  52. package/scaffold/pt-br/templates/idea-onepager.md +1 -1
  53. package/scaffold/skills/api-testing-recipes/SKILL.md +104 -0
  54. package/scaffold/skills/api-testing-recipes/recipes/dotnet-webapp-factory.md +168 -0
  55. package/scaffold/skills/api-testing-recipes/recipes/http-rest-client.md +130 -0
  56. package/scaffold/skills/api-testing-recipes/recipes/pytest-httpx.md +157 -0
  57. package/scaffold/skills/api-testing-recipes/recipes/rust-reqwest.md +173 -0
  58. package/scaffold/skills/api-testing-recipes/recipes/supertest-node.md +153 -0
  59. package/scaffold/skills/api-testing-recipes/references/auth-patterns.md +138 -0
  60. package/scaffold/skills/api-testing-recipes/references/log-conventions.md +117 -0
  61. package/scaffold/skills/api-testing-recipes/references/matrix-conventions.md +68 -0
  62. package/scaffold/skills/api-testing-recipes/references/openapi-driven.md +97 -0
  63. package/scaffold/skills/dw-codebase-intel/SKILL.md +101 -0
  64. package/scaffold/skills/dw-codebase-intel/agents/intel-updater.md +318 -0
  65. package/scaffold/skills/dw-codebase-intel/references/incremental-update.md +79 -0
  66. package/scaffold/skills/dw-codebase-intel/references/intel-format.md +208 -0
  67. package/scaffold/skills/dw-codebase-intel/references/query-patterns.md +148 -0
  68. package/scaffold/skills/dw-execute-phase/SKILL.md +133 -0
  69. package/scaffold/skills/dw-execute-phase/agents/executor.md +264 -0
  70. package/scaffold/skills/dw-execute-phase/agents/plan-checker.md +215 -0
  71. package/scaffold/skills/dw-execute-phase/references/atomic-commits.md +143 -0
  72. package/scaffold/skills/dw-execute-phase/references/plan-verification.md +156 -0
  73. package/scaffold/skills/dw-execute-phase/references/wave-coordination.md +102 -0
@@ -0,0 +1,138 @@
1
+ # Auth patterns — how to wire credentials into API tests
2
+
3
+ Tests need real credentials, but credentials must never live in the script files (which are committed). This file describes how each recipe handles the four common auth schemes and where credentials come from.
4
+
5
+ ## The four schemes
6
+
7
+ | Scheme | How it travels | Recipe handling |
8
+ |--------|----------------|-----------------|
9
+ | **Bearer JWT** | `Authorization: Bearer <token>` | Most common. Token comes from a login response or pre-issued for QA. |
10
+ | **Cookie session** | `Cookie: session=<sid>` (set by `Set-Cookie` on login) | Recipes capture the cookie from a login call and replay it. |
11
+ | **API key** | `X-API-Key: <key>` (header) or `?api_key=<key>` (query) | Header form is preferred; key comes from a per-environment env var. |
12
+ | **Basic auth** | `Authorization: Basic <base64(user:pass)>` | Rare in modern APIs; supported but discouraged. |
13
+
14
+ ## Where credentials come from (in priority order)
15
+
16
+ 1. **`.env` file** at the repo root, gitignored. Contains `QA_TOKEN_ADMIN`, `QA_ADMIN_EMAIL`, `QA_ADMIN_PASSWORD`, etc.
17
+ 2. **Pre-issued QA tokens** — long-lived JWTs minted by an admin tool (e.g., a `make qa-tokens` target) and stored in `.env`. Best for CI; avoids login-time flake.
18
+ 3. **Login at runtime** — a setup request hits `/auth/login` with `QA_ADMIN_EMAIL` + `QA_ADMIN_PASSWORD` and captures the token. Use when no pre-issued option exists.
19
+ 4. **`.dw/templates/qa-test-credentials.md`** — the project-level QA credentials registry that `dw-run-qa` already reads (UI mode). API mode reads the same file for env-var hints + role mapping.
20
+
21
+ ## Three roles every project should have
22
+
23
+ Even for single-tenant apps, define at minimum:
24
+
25
+ - **`token_admin`** — has every permission. Used for setup (create test data) and teardown.
26
+ - **`token_user`** — regular authenticated user. The role most happy-path tests run as.
27
+ - **`token_guest`** OR **`token_other_org_admin`** — for negative tests. In multi-tenant apps, this token belongs to a different org and powers the cross-tenant denial tests.
28
+
29
+ ## Per-recipe variable conventions
30
+
31
+ ### `.http` (REST Client)
32
+
33
+ Top of the file:
34
+
35
+ ```http
36
+ @base = {{$dotenv API_BASE_URL}}
37
+ @token_admin = {{$dotenv QA_TOKEN_ADMIN}}
38
+ @token_user = {{$dotenv QA_TOKEN_USER}}
39
+ @token_other_org = {{$dotenv QA_TOKEN_OTHER_ORG}}
40
+ ```
41
+
42
+ Or, if logging in at runtime, capture once and reuse:
43
+
44
+ ```http
45
+ ### Setup — login as admin
46
+ # @name login_admin
47
+ POST {{base}}/auth/login
48
+ Content-Type: application/json
49
+ { "email": "{{$dotenv QA_ADMIN_EMAIL}}", "password": "{{$dotenv QA_ADMIN_PASSWORD}}" }
50
+
51
+ > {%
52
+ client.global.set("token_admin", response.body.access_token);
53
+ client.test("login ok", () => client.assert(response.status === 200));
54
+ %}
55
+ ```
56
+
57
+ ### `pytest + httpx`
58
+
59
+ Read from environment in module scope; expose as fixtures if the test count grows:
60
+
61
+ ```python
62
+ TOKEN_ADMIN = os.environ["QA_TOKEN_ADMIN"]
63
+ TOKEN_USER = os.environ["QA_TOKEN_USER"]
64
+ TOKEN_OTHER_ORG = os.environ.get("QA_TOKEN_OTHER_ORG", "")
65
+
66
+ @pytest.fixture(scope="session")
67
+ async def admin_client():
68
+ async with httpx.AsyncClient(base_url=BASE,
69
+ headers={"Authorization": f"Bearer {TOKEN_ADMIN}"},
70
+ timeout=10.0) as c:
71
+ yield c
72
+ ```
73
+
74
+ ### `supertest` (Node)
75
+
76
+ Same `process.env` reads, optionally one helper per role:
77
+
78
+ ```ts
79
+ const auth = (token: string) => ({ Authorization: `Bearer ${token}` });
80
+ const TOKEN_ADMIN = process.env.QA_TOKEN_ADMIN!;
81
+ ```
82
+
83
+ ### `WebApplicationFactory` (.NET)
84
+
85
+ Subclass the factory once per role:
86
+
87
+ ```csharp
88
+ public class AdminAppFactory : WebApplicationFactory<Program>
89
+ {
90
+ protected override void ConfigureClient(HttpClient client)
91
+ {
92
+ client.DefaultRequestHeaders.Authorization =
93
+ new AuthenticationHeaderValue("Bearer",
94
+ Environment.GetEnvironmentVariable("QA_TOKEN_ADMIN") ?? "");
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### `reqwest` (Rust)
100
+
101
+ Helper functions read env once:
102
+
103
+ ```rust
104
+ fn token_admin() -> String { std::env::var("QA_TOKEN_ADMIN").unwrap_or_default() }
105
+ fn admin_client() -> reqwest::Client {
106
+ reqwest::Client::builder().build().unwrap()
107
+ }
108
+ // then: admin_client().get(url).bearer_auth(token_admin()).send().await
109
+ ```
110
+
111
+ ## Refresh tokens
112
+
113
+ If the API uses refresh tokens, capture both `access_token` and `refresh_token` in the login setup. When a test needs a long-lived flow (e.g., wait for a webhook), refresh the access token before the wait.
114
+
115
+ For most QA suites, the access token's TTL (typically 15-60 min) is longer than the suite's runtime, so refresh is unnecessary.
116
+
117
+ ## Scoped credentials per role
118
+
119
+ For RBAC-heavy systems, define more roles:
120
+
121
+ - `token_admin` — global admin
122
+ - `token_org_admin` — admin within one org
123
+ - `token_member` — regular member of one org
124
+ - `token_billing` — read-only billing access
125
+ - `token_other_org_admin` — admin of a different org (for cross-tenant tests)
126
+
127
+ Add one env var per role; the recipe reads them as needed. Tests that don't need a particular role just don't reference it.
128
+
129
+ ## Anti-patterns
130
+
131
+ - **Don't hardcode `Bearer eyJ...` in any committed file.** Even "test" tokens leak.
132
+ - **Don't share one token across happy-path AND negative tests.** If a happy-path test mutates the token's user (e.g., suspends it), every later test fails.
133
+ - **Don't reuse production tokens for QA.** Mint QA-only tokens with a clearly distinct subject (`sub: qa-admin@example.com`).
134
+ - **Don't pass credentials via command-line args.** They land in shell history and process listings.
135
+
136
+ ## What `dw-run-qa` does
137
+
138
+ In API mode, `/dw-run-qa` reads `QA/test-credentials.md` (or `.env`) for the env var names, picks the recipe, and substitutes variables at test-generation time. The script files reference `@variable` references only — never raw tokens.
@@ -0,0 +1,117 @@
1
+ # Log conventions — request/response evidence as JSONL
2
+
3
+ In API mode, **logs replace screenshots** as the primary QA evidence. Every request/response pair the QA suite makes is captured as one JSONL line so the bug report links back to a reproducible event.
4
+
5
+ ## File location
6
+
7
+ `{{PRD_PATH}}/QA/logs/api/<scope>.log`
8
+
9
+ Where `<scope>` is one of:
10
+
11
+ - `RF-XX-[slug].log` — log for a single requirement run (1 file per RF).
12
+ - `BUG-NN-retest.log` — log for a fix retest (1 file per bug retest cycle).
13
+ - `run-<YYYY-MM-DD>.log` — global run log (full QA pass).
14
+
15
+ ## Line shape (JSONL — one JSON object per line)
16
+
17
+ ```json
18
+ {
19
+ "ts": 1715000000000,
20
+ "rf": "RF-03",
21
+ "case": "happy-path",
22
+ "method": "POST",
23
+ "url": "http://localhost:3000/users",
24
+ "request_headers": {
25
+ "authorization": "Bearer <redacted>",
26
+ "content-type": "application/json"
27
+ },
28
+ "request_body": {
29
+ "email": "qa-1@example.com",
30
+ "name": "QA"
31
+ },
32
+ "status": 201,
33
+ "response_headers": {
34
+ "content-type": "application/json",
35
+ "location": "/users/12345"
36
+ },
37
+ "response_body": {
38
+ "id": "12345",
39
+ "email": "qa-1@example.com",
40
+ "name": "QA",
41
+ "created_at": "2026-05-06T12:00:00Z"
42
+ },
43
+ "ms": 47,
44
+ "verdict": "PASS",
45
+ "assertion_failures": []
46
+ }
47
+ ```
48
+
49
+ ## Required fields
50
+
51
+ | Field | Type | Notes |
52
+ |-------|------|-------|
53
+ | `ts` | int (epoch ms, UTC) | When the request was sent |
54
+ | `rf` | string | Which `RF-XX` this request belongs to (or `"BUG-NN"` for retests) |
55
+ | `case` | string | One of `happy-path`, `validation`, `auth-missing`, `auth-expired`, `authz-cross-tenant`, `not-found`, `conflict`, `server-error`, `contract` |
56
+ | `method` | string | HTTP method |
57
+ | `url` | string | Full URL including query string |
58
+ | `status` | int | HTTP status code |
59
+ | `ms` | int | Elapsed milliseconds |
60
+ | `verdict` | string | `"PASS"` or `"FAIL"` |
61
+ | `assertion_failures` | array of strings | Each failed assertion as a one-line description (empty array on PASS) |
62
+
63
+ ## Optional fields
64
+
65
+ | Field | Type | Notes |
66
+ |-------|------|-------|
67
+ | `request_headers` | object | Map of header name → value |
68
+ | `request_body` | any | Parsed JSON if `Content-Type: application/json`; raw string otherwise |
69
+ | `response_headers` | object | Same shape as request_headers |
70
+ | `response_body` | any | Parsed JSON if `Content-Type: application/json`; raw string otherwise |
71
+ | `err` | string | Network/runtime error message (if no response was received at all) |
72
+
73
+ ## Redaction rules
74
+
75
+ The log goes to `QA/logs/api/` which **may end up in artifacts uploaded to CI** or attached to bug reports. Redact:
76
+
77
+ - **`Authorization` header** → `"Bearer <redacted>"` or `"Basic <redacted>"`. The token's presence is logged; the value never is.
78
+ - **`Cookie` header** → `"<redacted>"`. Same reasoning.
79
+ - **`X-API-Key` header** → `"<redacted>"`.
80
+ - **Response fields named `password*`, `secret*`, `*_hash`, `token*`, `apiKey*`** → `"<redacted>"`. These should never be in a response anyway; if they are, the log redacts AND the QA report flags the leak.
81
+ - **Free-form `request_body` fields named `password`** → `"<redacted>"`.
82
+
83
+ The redaction is applied at log-write time, never on read; even a leaked log file should not expose secrets.
84
+
85
+ ## Why JSONL (not pretty-printed JSON)
86
+
87
+ - **Append-friendly**: each request is one line; concurrent runs append safely without parsing the whole file.
88
+ - **Greppable**: `grep '"verdict":"FAIL"' QA/logs/api/RF-03.log` shows every failed case in one shot.
89
+ - **Queryable**: `jq -c 'select(.status >= 500)' QA/logs/api/run-*.log | jq -s 'group_by(.url) | map({url: .[0].url, count: length})'` finds the most-failing URLs.
90
+ - **Diffable across runs**: `diff <(jq -c 'del(.ts, .ms)' RF-03.log) <(jq -c 'del(.ts, .ms)' RF-03.log.prev)` shows behavior changes free of timing noise.
91
+
92
+ ## Per-recipe writers
93
+
94
+ Every recipe in `recipes/` includes a small writer helper in its example:
95
+
96
+ - `.http` — the agent writes via `Bash` after each `curl` invocation.
97
+ - `pytest+httpx` — `LoggingClient` subclass overriding `request`.
98
+ - `supertest` — small `logRequest` helper imported by tests.
99
+ - `.NET WebApplicationFactory` — `DelegatingHandler` registered on the test client.
100
+ - `reqwest` — wrapper function around `client.execute(req)`.
101
+
102
+ All of them produce the same JSONL shape so downstream tooling (the QA report renderer, the bug retest loop) doesn't care which recipe was used.
103
+
104
+ ## How `dw-run-qa` reads logs back
105
+
106
+ When generating the QA report (Step 8 in `dw-run-qa`), the agent reads each `RF-XX-[slug].log`, computes:
107
+
108
+ - **Total requests** per RF
109
+ - **Pass count vs fail count**
110
+ - **Failing cases** with the assertion message
111
+ - **Tail latency** (p99 if there are ≥10 requests, max otherwise)
112
+
113
+ These land in the report's "Verified Requirements" table and feed the bug entries (with `evidence_path: QA/logs/api/RF-03.log#L42` pointing to the failing line).
114
+
115
+ ## How `dw-fix-qa` consumes them
116
+
117
+ The retest loop reads `QA/bugs.md` for each open bug, finds the corresponding log line via `evidence_path`, replays the request via the same recipe + assertions, and writes a new line to `BUG-NN-retest.log` with `verdict: "PASS"` (closing the bug) or `verdict: "FAIL"` (cycling through the fix-retest loop again, max 5 cycles).
@@ -0,0 +1,68 @@
1
+ # Matrix conventions — deriving tests from a PRD requirement
2
+
3
+ Every API requirement (`RF-XX`) gets a structured matrix of test cases. The matrix is the bridge between "the PRD says this endpoint must exist" and "we have evidence it works under the cases that matter."
4
+
5
+ ## The five tiers
6
+
7
+ For each `RF-XX`, generate at least one test per tier that applies:
8
+
9
+ | Tier | Goal | When to skip |
10
+ |------|------|--------------|
11
+ | **200 happy path** | Prove the endpoint accepts the documented input and returns the documented output. | Never — every RF needs at least one happy path. |
12
+ | **4xx — validation** | Prove input validation rejects malformed payloads with a useful error. | Skip only for endpoints with no body (`GET` without query params). |
13
+ | **4xx — auth (401)** | Prove missing/expired/invalid credentials return 401. | Skip for endpoints documented as anonymous. |
14
+ | **4xx — authorization (403)** | Prove valid credentials without the required role/scope return 403. | Skip if the endpoint is open to any authenticated user. |
15
+ | **4xx — not found (404)** | Prove non-existent IDs return 404, not 500. | Skip for endpoints that don't take an ID. |
16
+ | **4xx — conflict (409)** | Prove duplicates / version mismatches return 409. | Skip if the endpoint is idempotent and conflict-free by design. |
17
+ | **5xx — server error** | Prove the system fails gracefully (no leaked stack trace, no half-write). | Skip if no synthetic failure is reproducible without invasive infrastructure changes. |
18
+ | **Contract drift** | Prove the response shape matches the documented spec (OpenAPI, TS types, README examples). | Never — this is the cheapest way to catch silent breakage. |
19
+ | **Authorization cross-tenant** | Prove tokens from org A cannot access data of org B. | Skip only for single-tenant systems (rare in practice). |
20
+
21
+ ## Why the cross-tenant test is mandatory
22
+
23
+ Cross-tenant data leakage is the most damaging API bug class — it's silent (no error), undetected by happy-path tests, and lethal in B2B SaaS. Every endpoint that returns or mutates tenant-scoped data must have a cross-tenant denial test. If the project is single-tenant, mark the test `pytest.skip` / `it.skip` / `[Fact(Skip="single-tenant")]` instead of omitting — the explicit skip is a record of the decision.
24
+
25
+ ## How to enumerate inputs per tier
26
+
27
+ For each tier, ask:
28
+
29
+ - **200**: what's the minimum valid payload? Build the test around that. Add 2-3 variations only if the endpoint has interesting branching (nullable fields, enum variants, optional sections).
30
+ - **4xx validation**: what fields are required? Drop each one. What types are constrained? Send the wrong type. What ranges? Test min-1 and max+1. Don't test all combinations — one per kind of constraint is enough.
31
+ - **4xx auth**: 3 variants — no token, expired token, malformed token. One test for each is enough.
32
+ - **4xx authorization**: identify role boundaries (admin vs user vs guest, owner vs member). One test per boundary.
33
+ - **4xx not found**: 1 test with a syntactically-valid-but-nonexistent ID (UUID, integer, etc.).
34
+ - **4xx conflict**: 1 test that triggers the documented conflict (duplicate email, race on version).
35
+ - **5xx**: skip if not reproducible. If the project has a way to inject failures (chaos hooks, dev-only error endpoints), use them.
36
+ - **Contract drift**: 1 test that asserts every documented field is present AND no leaked internal field is.
37
+ - **Cross-tenant**: 1 test per tenant-scoped endpoint with a token from a different tenant.
38
+
39
+ ## Example expansion: `POST /users`
40
+
41
+ PRD says: "RF-03 — admins can create users. Validation: email is required and must be unique. Returns 201 with the new user."
42
+
43
+ Matrix:
44
+
45
+ | # | Tier | Case | Expected |
46
+ |---|------|------|----------|
47
+ | 1 | 200 | admin creates user with valid payload | 201, body has id |
48
+ | 2 | 4xx validation | missing email | 422, error mentions email |
49
+ | 3 | 4xx validation | invalid email format | 422 |
50
+ | 4 | 4xx auth | no token | 401 |
51
+ | 5 | 4xx auth | expired token | 401 |
52
+ | 6 | 4xx authorization | regular user (not admin) | 403 |
53
+ | 7 | 4xx conflict | email already taken | 409 |
54
+ | 8 | Contract | all required fields present, no `password_hash` | matches spec |
55
+ | 9 | Cross-tenant | admin from another org tries to fetch this user | 403 or 404 |
56
+
57
+ That's 9 test cases for one RF — the floor for a real API surface, not the ceiling.
58
+
59
+ ## What NOT to do
60
+
61
+ - **Don't test every combination** of validation failures. The framework already enforces type + presence; one test per kind of constraint is the signal.
62
+ - **Don't test the framework**. `Content-Type: application/json` parsing, default routing, etc. — those belong to FastAPI / Fastify / ASP.NET, not to your QA suite.
63
+ - **Don't write tests for endpoints with no PRD reference**. If a route exists but no RF describes it, that's a documentation gap to flag, not a test to add.
64
+ - **Don't skip 5xx because "it shouldn't happen"**. If you have a way to reproduce, do it. If you genuinely can't, document the skip in the QA report so the gap is visible.
65
+
66
+ ## How `dw-run-qa` uses this
67
+
68
+ When in API mode, `/dw-run-qa` walks each `RF-XX` in the PRD, runs through this matrix, and emits PASS/FAIL per RF — not per test case. A single FAIL in any tier marks the RF as FAIL and lands a `BUG-NN` entry pointing to the failing log line.
@@ -0,0 +1,97 @@
1
+ # OpenAPI-driven mode — generating tests from a spec
2
+
3
+ When the project exposes an OpenAPI spec (static `openapi.yaml`/`openapi.json`, or dynamic `/openapi.json` for FastAPI), `/dw-run-qa` can derive a baseline test suite directly from it. This catches contract drift between code and spec for free.
4
+
5
+ ## When to use this mode
6
+
7
+ - The project already maintains an OpenAPI spec — either hand-written, generated from code annotations (FastAPI, NestJS + `@nestjs/swagger`, dotnet Swashbuckle), or synced via a code generator.
8
+ - You want a quick "is this endpoint reachable AND does its response shape match the spec?" check.
9
+ - You want to detect when code drifts ahead of (or behind) the spec.
10
+
11
+ ## What it generates
12
+
13
+ For each path × method in the spec:
14
+
15
+ 1. A **happy-path test** using the spec's `requestBody` example (or schema-derived sample).
16
+ 2. A **contract-shape test** asserting the response matches the documented schema.
17
+ 3. Skips paths/methods marked with the `x-internal: true` extension or those without examples.
18
+
19
+ The generated tests live alongside hand-written ones in `{{PRD_PATH}}/QA/scripts/api/`. Filename pattern: `openapi-RF-XX-[path-slug].http` (or stack-specific extension).
20
+
21
+ ## How to run it
22
+
23
+ `/dw-run-qa --from-openapi <spec-path-or-url>` — explicit. The `<spec-path-or-url>` can be:
24
+
25
+ - `./openapi.yaml`
26
+ - `http://localhost:3000/openapi.json` (FastAPI default)
27
+ - `http://localhost:3000/swagger/v1/swagger.json` (ASP.NET Core default)
28
+
29
+ Without the flag, `/dw-run-qa` auto-detects:
30
+
31
+ - File at repo root: `openapi.yaml`, `openapi.json`, `swagger.yaml`, `swagger.json`.
32
+ - Project running locally: `GET /openapi.json`, `GET /swagger/v1/swagger.json`, `GET /api-docs`.
33
+
34
+ If found, the agent asks: "OpenAPI spec detected at `<path>`. Generate baseline tests from it? [y/n]". On `y`, the baseline is added on top of the PRD-derived matrix.
35
+
36
+ ## Mapping spec endpoints to RFs
37
+
38
+ The PRD names requirements (`RF-01`, `RF-02`); the spec names paths (`/users`, `/orders/{id}`). Two conventions for cross-referencing:
39
+
40
+ - **By tag**: tests for a path tagged `users` map to the PRD section also tagged `users`. Cleanest if the project keeps tags consistent.
41
+ - **By summary keyword**: the spec's `summary` field is matched against PRD requirement titles. Less reliable; only use as a fallback.
42
+
43
+ If neither matches, the test lands as `openapi-no-rf-[slug].http` and the QA report flags it as "spec endpoint not mapped to any RF — possible documentation gap."
44
+
45
+ ## Contract drift detection
46
+
47
+ For each response from a generated test, compare:
48
+
49
+ 1. **Status code** — does the actual status appear in the spec's `responses` block?
50
+ 2. **Required fields** — every field marked `required: true` in the schema must be present.
51
+ 3. **Type matching** — `email: string` in spec, but actual is `email: null`? Fail.
52
+ 4. **No leaked fields** — fields NOT in the spec but present in the response are flagged as **drift forward** (code added a field; spec is stale).
53
+ 5. **Sensitive defaults** — fields named `password*`, `secret*`, `token*`, `*_hash` in the response trigger an immediate FAIL with severity HIGH, even if they're "documented."
54
+
55
+ ## Generating example payloads
56
+
57
+ If the spec has `example` or `examples`, use them verbatim. If only schemas exist, sample using a deterministic strategy:
58
+
59
+ | JSON Schema type | Sample value |
60
+ |-------|-------|
61
+ | `string` | `"qa-string"` (or `"qa@example.com"` if `format: email`, ISO date if `format: date-time`, UUID v4 if `format: uuid`) |
62
+ | `integer` | `1` (or value within `minimum`/`maximum` if set) |
63
+ | `number` | `1.0` |
64
+ | `boolean` | `true` |
65
+ | `array` | one element of the inner type |
66
+ | `object` | recurse on `properties`; only include `required` fields |
67
+ | `enum` | first value |
68
+ | `oneOf`/`anyOf` | first variant |
69
+
70
+ Skip endpoints whose request shape can't be sampled deterministically (e.g., free-form JSON without schema, file uploads requiring real binary data).
71
+
72
+ ## What NOT to do
73
+
74
+ - **Don't replace the PRD-derived matrix with OpenAPI-only tests.** OpenAPI tells you what the code claims to do; the PRD tells you what the product needs. Both matter. Keep both.
75
+ - **Don't trust the spec implicitly.** If `dw-run-qa` finds 0 drift on day 1 and the team has been shipping for 6 months, the spec is probably stale, not the code. Flag the suspicion in the QA report.
76
+ - **Don't generate tests for `x-internal: true` endpoints.** Those are behind an internal-network boundary; QA on them needs different credentials and risk profile.
77
+
78
+ ## Limitations
79
+
80
+ - Doesn't generate authorization tests automatically (the spec doesn't say "this endpoint should reject other-tenant tokens"). Hand-write those per the cross-tenant pattern in `matrix-conventions.md`.
81
+ - Doesn't generate state-mutating sequences (create → update → delete). Those need PRD context to know what state matters.
82
+ - Treats the spec as authoritative for contract drift, but not for behavior. A spec that's wrong is still going to fail tests against correct code — and that's the right outcome. Update the spec.
83
+
84
+ ## What `dw-run-qa` produces
85
+
86
+ When OpenAPI mode runs, the QA report gains a section:
87
+
88
+ ```markdown
89
+ ## OpenAPI baseline
90
+
91
+ - Spec source: openapi.yaml (53 paths, 121 operations)
92
+ - Endpoints sampled: 89 (32 skipped: missing examples, file uploads, `x-internal`)
93
+ - Drift detected: 4 endpoints (see RF-12, RF-15, RF-22, openapi-no-rf-internal-metrics)
94
+ - Contract issues:
95
+ - RF-12 — `email` documented as required, response returns null
96
+ - openapi-no-rf-internal-metrics — endpoint exists in spec but no PRD reference
97
+ ```
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: dw-codebase-intel
3
+ description: Codebase intelligence for dev-workflow. The intel-updater agent maintains a queryable index in .dw/intel/ (stack.json, files.json, apis.json, deps.json, arch.md) that other commands read instead of doing expensive codebase exploration. Used by /dw-intel and /dw-map-codebase. Adapted from get-shit-done-cc (MIT).
4
+ allowed-tools:
5
+ - Read
6
+ - Write
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ ---
11
+
12
+ # dw-codebase-intel
13
+
14
+ Bundled skill that gives dev-workflow native **codebase intelligence** — a queryable knowledge base of the project's stack, file graph, API surface, dependencies, and architecture. Other commands (`/dw-create-prd`, `/dw-create-techspec`, `/dw-code-review`, `/dw-refactoring-analysis`, `/dw-brainstorm`, etc.) read from this index instead of re-exploring the codebase on every invocation.
15
+
16
+ ## Why a skill (not inline)
17
+
18
+ - Each agent is independently maintainable and reusable.
19
+ - The format of `.dw/intel/` is a contract that downstream commands depend on; codifying it in references makes drift visible.
20
+ - Other commands invoke these agents through the skill, not by duplicating the logic.
21
+
22
+ ## When to Use
23
+
24
+ Read this skill when:
25
+
26
+ - `/dw-map-codebase` is invoked (full or partial codebase analysis).
27
+ - `/dw-intel "<query>"` is invoked (query existing intel).
28
+ - `/dw-analyze-project` runs after first commit and wants to enrich `.dw/rules/` with structural facts from `.dw/intel/`.
29
+ - Any other `dw-*` command wants to look up "where is X used", "what frameworks are in this stack", "what's the architecture pattern" without re-scanning files.
30
+
31
+ Do NOT use when:
32
+
33
+ - The user is asking a runtime question (use logs / running app).
34
+ - The intel is fresh (`.dw/intel/.last-refresh.json` is current and the user did not ask for a refresh).
35
+ - The project is greenfield with no source files yet — in that case, fall back to `.dw/rules/` seeded by `/dw-new-project`.
36
+
37
+ ## Files in `.dw/intel/`
38
+
39
+ The intel directory is the contract. Every file is machine-parseable and references real file paths.
40
+
41
+ | File | Purpose | Format |
42
+ |------|---------|--------|
43
+ | `stack.json` | Languages, frameworks, build/test tooling, package manager | JSON |
44
+ | `files.json` | File graph: per-file imports/exports/type | JSON |
45
+ | `apis.json` | API surface: routes, methods, params, source file | JSON |
46
+ | `deps.json` | Dependencies: version, type, used_by, invocation | JSON |
47
+ | `arch.md` | Human-readable architecture overview + key components + data flow | Markdown |
48
+ | `.last-refresh.json` | Timestamps + content hashes for incremental detection | JSON |
49
+
50
+ Schemas are documented in `references/intel-format.md`.
51
+
52
+ ## Agents
53
+
54
+ | Agent | Responsibility | Spawn from |
55
+ |-------|----------------|------------|
56
+ | `agents/intel-updater.md` | Reads source files, writes structured intel to `.dw/intel/`. Supports `full` or `partial --files <paths>` updates. | `/dw-map-codebase` |
57
+
58
+ This skill ships ONE agent — `intel-updater` — which produces machine-readable JSON for `/dw-intel` queries. Human-readable architecture analysis (per-module conventions, anti-patterns, code smells) lives in `.dw/rules/` and is generated by `/dw-analyze-project`. The two are complementary: `.dw/intel/` answers "what's in this codebase right now?" and `.dw/rules/` answers "how should we write code here?".
59
+
60
+ ## How to Compose (the typical flow)
61
+
62
+ 1. **`/dw-map-codebase`** is invoked.
63
+ 2. The command spawns `intel-updater` with `focus: full` (first run) or `focus: partial --files <paths>` (incremental).
64
+ 3. The agent reads source files (using Glob/Read/Grep; no Bash file listing for cross-platform safety) and writes the 5 intel files.
65
+ 4. The agent writes `.last-refresh.json` with timestamps + hashes for incremental change detection on the next run.
66
+ 5. `/dw-map-codebase` reports completion and invites the user to query via `/dw-intel "<question>"`.
67
+
68
+ For human-readable analysis (architecture overview, module conventions, anti-patterns), run `/dw-analyze-project` after `/dw-map-codebase` — it reads `.dw/intel/` as input and produces `.dw/rules/`.
69
+
70
+ ## How `/dw-intel` Reads This
71
+
72
+ `/dw-intel "auth flow"` does:
73
+
74
+ 1. Check `.dw/intel/.last-refresh.json` — is the index fresh (within last 7 days)? If stale, suggest re-running `/dw-map-codebase`.
75
+ 2. Search `apis.json` for matching paths/descriptions.
76
+ 3. Search `files.json` for matching exports.
77
+ 4. Search `arch.md` (full-text) for the keyword.
78
+ 5. Cross-reference with `deps.json` if the query is about a library.
79
+ 6. Return a structured answer with file paths cited.
80
+
81
+ If no `.dw/intel/` exists at all, `/dw-intel` falls back to `.dw/rules/` (seeded by `/dw-new-project` or `/dw-analyze-project`) and direct grep over the codebase.
82
+
83
+ ## Rules
84
+
85
+ - **Always cite file paths.** Every claim in intel must reference an actual file location.
86
+ - **Current state only.** No temporal language ("recently added", "will change"). The index reflects what's there NOW.
87
+ - **Evidence-based.** Read actual files. Never guess from filenames or directory structures.
88
+ - **Cross-platform**: use Glob/Read/Grep; never Bash `ls`/`find`/`cat` (those break on Windows).
89
+ - **Forbidden files**: never read `.env*` (except `.env.example`/`.env.template`), `*.key`, `*.pem`, `*.pfx`, `*.p12`, `*.keystore`, `*.jks`, `id_rsa`, `id_ed25519`, or files matching `*credential*`/`*secret*` in name. Skip silently if encountered.
90
+ - **Excluded directories**: `node_modules/`, `.git/`, `dist/`, `build/`, `.dw/` (planning docs, not project code).
91
+ - **Output budget**: `files.json` ≤2K tokens, `apis.json` ≤1.5K, `deps.json` ≤1K, `stack.json` ≤500, `arch.md` ≤1.5K. For large repos, prioritize coverage of key files over exhaustive listing.
92
+
93
+ ## References
94
+
95
+ - `references/intel-format.md` — schema for each `.dw/intel/` file with examples.
96
+ - `references/incremental-update.md` — how partial updates work (which files to re-read, how to merge with existing entries).
97
+ - `references/query-patterns.md` — how `/dw-intel` answers different question shapes (where-is, what-uses, architecture-of, dependency-of).
98
+
99
+ ## Inspired by
100
+
101
+ Adapted from [`get-shit-done-cc`](https://github.com/gsd-build/get-shit-done) (`gsd-intel-updater`) by gsd-build (MIT license). Core schemas (`files.json`, `apis.json`, `deps.json`, `stack.json`, `arch.md`) and incremental update protocol preserved. Path conventions changed from `.planning/intel/` to `.dw/intel/`. CLI tooling (`gsd-sdk query intel.*`) replaced by agent-driven inline operations (no separate runtime). The companion `gsd-codebase-mapper` agent (human-readable analysis docs) was NOT ported — its scope overlaps with the existing `/dw-analyze-project` command which writes to `.dw/rules/`.