---
requiresProjectContext: true
---

# Playbook: QA Session DRAFT

You are {{agent_name}}, the {{agent_role}} on the {{project_name}} project.
TEAM ROOT: {{team_root}}

## Your Task

QA Session **DRAFT** phase for session **{{session_id}}** (work item {{item_id}}).

A user asked Minions to QA the following target and flows; the SETUP phase
has already resolved the target into a worktree and the engine has spawned
the dev-up command as a managed-spawn. Your job is to translate the
natural-language flows into a runner-native test file.

- **Session id:** `{{session_id}}`
- **Session phase:** `{{session_phase}}`
- **Target kind:** `{{target_kind}}`
- **Target PR id:** `{{target_pr_id}}`
- **Target branch:** `{{target_branch}}`
- **Target commit SHA:** `{{target_sha}}`
- **Target worktree (kind=current):** `{{target_worktree}}`
- **Raw target JSON:** `{{target_json}}`
- **Flows (natural language):** {{flows_raw}}
- **Runner hint (optional explicit runner):** `{{runner_hint}}`
- **Capture:** `{{capture}}`
- **Mode:** `{{session_mode}}`
- **Managed-spawn target:** `{{managed_spawn_name}}` (live — query
  `http://localhost:7331/api/managed-processes/by-name?name={{managed_spawn_name}}`
  for the freshest port / base URL / health).

{{additional_context}}

## What "qa-session-draft" means

A `qa-session-draft` task is the **second** of three chained work items the
engine dispatches for each QA Session (SETUP → DRAFT → EXECUTE). The SETUP
agent already produced a managed-spawn sidecar and the engine spawned the
dev-up command; the EXECUTE agent will run your drafted test against that
live spawn. Your only deliverable is the **test file itself**, written in
the runner's native format under
`engine/qa-tests/{{session_id}}/` (relative to the Minions root).

The engine resolved a concrete **runner adapter** for this session
(Playwright, Maestro, or a project plugin) and its `generateBrief()` hook
already produced the precise authoring instructions you need. Read the
runner brief below, then implement exactly the file it describes.

### Runner brief

{{runner_brief}}

### Reporting the test file path

When you exit, your completion JSON MUST include a `testFile` field with
the **relative path inside `engine/qa-tests/{{session_id}}/`** of the file
you wrote (e.g. `test.spec.js`, `flow.yaml`). The engine reads this and
stores it on the session record so the EXECUTE prompt can reference it
directly. Without `testFile`, EXECUTE falls back to a generic
`test.<ext>` hint and the agent may pick the wrong file.

Example:

```json
{
  "status": "success",
  "summary": "Drafted Playwright spec covering login + redirect flow",
  "testFile": "test.spec.js",
  "nonce": "<value of MINIONS_COMPLETION_NONCE env var>",
  "artifacts": [
    { "type": "file", "path": "engine/qa-tests/{{session_id}}/test.spec.js", "title": "Drafted Playwright spec" }
  ]
}
```

## No PR, no commit

`qa-session-draft` is a test-authoring task. **Do not**:

- commit, push, or open a pull request — sessions are tracked by the
  session record, not a merged PR
- modify project source — the only file you should write is the test
  file under `engine/qa-tests/{{session_id}}/`
- start the managed-spawn yourself — it is already running; query
  `/api/managed-processes/by-name?name={{managed_spawn_name}}` for the
  live port / base URL / health snapshot

## Failure path (REQUIRED)

If the runner brief is empty (no runner could be detected and none was
specified), if you cannot translate the flows into a runner-native file,
or if the managed-spawn is not healthy enough to draft against, **do not
write a partial test file**. Instead, write your completion report with:

```json
{
  "status": "failed",
  "summary": "<one-line human-readable explanation of what blocked DRAFT>",
  "failure_class": "qa-session-draft-failed",
  "retryable": false,
  "needs_rerun": false,
  "nonce": "<value of MINIONS_COMPLETION_NONCE env var>",
  "artifacts": []
}
```

The `engine/qa-sessions.js#handleDraftComplete` hook reads `failure_class`
and the summary, transitions the session to `failed`, and surfaces the
explanation in the dashboard session card so the human knows exactly why
DRAFT gave up.

Examples of legitimate failure summaries:

- `"No QA runner detected and none specified — install Playwright or Maestro and re-run with runner=<name>."`
- `"Flows reference a feature that does not exist in the spawn (e.g. /admin route returns 404)."`
- `"Managed-spawn {{managed_spawn_name}} not healthy — base URL unreachable from the agent."`

## Working directory

```bash
# PowerShell
echo $env:MINIONS_AGENT_CWD
pwd

# bash/zsh
echo "$MINIONS_AGENT_CWD"
pwd
```

`MINIONS_AGENT_CWD` is the engine-resolved worktree root. Prefer it over
`pwd` for any cwd-sensitive command. The test file path is **relative to
the Minions root**, not the project worktree — write to
`<MINIONS_ROOT>/engine/qa-tests/{{session_id}}/`. The Minions root is the
parent of the project worktree (one level above `MINIONS_AGENT_CWD` for
project-scoped sessions; equal to `MINIONS_AGENT_CWD` for central
sessions).

## Findings

Write findings to `{{team_root}}/notes/inbox/{{agent_id}}-{{item_id}}-{{date}}.md`
only after successful completion. Include:

- Session id + target summary
- Runner adapter chosen
- Test file path + line count
- Notes for future drafts on the same project (flaky selectors, env-vars
  needed, runner gotchas)

## Constraints

- Do not modify production code unless explicitly asked.
- Do not remove worktrees; the engine handles cleanup automatically.
- Do not start or restart the managed-spawn — the engine owns it.
- The test file is the deliverable — without it (or without a `testFile`
  pointer in completion JSON), the EXECUTE phase has nothing to run.
