Agent Phases
Phase 2: Test Design Agent
ContextPack from Phase 1 into a validated TestDesignPack: acceptance criteria, test strategy, Gherkin or manual scenarios, coverage matrices, risk ranking, open questions, and Xray upload results.This phase is where Testonaut stops being a generic test-case generator and starts behaving like a repository-aware QA architect. It does not only read the Jira story: when a target repository is available, it scans the existing Cucumber feature files and reuses the team's existing Gherkin step vocabulary so it does not create near-duplicate steps that later require duplicate step definitions.

Inputs and outputs
| Item | Description |
|---|---|
Input: ContextPack | Ticket context, comments, Confluence pages, attachments, linked tests, related tickets, evidence graph, provenance, and warnings from Phase 1. |
| Optional input: target repo | Local checkout used for repo skill overrides, existing .feature step reuse, and existing scenario de-duplication. |
| Optional input: Xray credentials | Enables creation of Cucumber or Manual tests in Xray, linked back to the story. |
Output: TestDesignPack | Validated test design artifact with ACs, scenarios, coverage, risk, source evidence, warnings, and optional Xray application result. |
| Output files | out/<KEY>/test-design.json, test-design.md, and generated .feature files for Gherkin mode. |
Where the repository connection belongs
Repository discovery starts from information gathered in Phase 1, but repository-aware step reuse belongs to Phase 2 because it directly changes how the Test Architect writes scenarios. There are two ways the design phase gets a repository:
| Source | Priority | How it works |
|---|---|---|
--repo <path> | Highest | The pipeline or user gives the local target repository path directly. |
Jira development section + TESTONAUT_REPO_ROOTS | Fallback | Phase 1 gathers branch/PR repository names from Jira development information. Phase 2 maps one of those names to a local checkout path. |
If no repository is resolved, Testonaut still designs tests, but it cannot reuse existing step phrasings. The CLI makes that visible with a message telling the user to pass --repo or configure TESTONAUT_REPO_ROOTS.

Key capability: repository-aware Gherkin step reuse
Most AI test generators can write plausible Cucumber scenarios, but they often create subtly different phrasings for behavior that the repository already supports. That causes duplicate Gherkin steps and duplicate step-definition code:
| Existing step | Bad generated near-duplicate |
|---|---|
Given the customer is logged in | Given the user has signed into the portal |
When I submit the payment form | When the payment form is submitted |
Then the instalment plan is displayed | Then I should see the instalment plan |
Humans understand those as equivalent. Cucumber does not — if the generated wording is different, the implementation phase may need new glue code even though equivalent step definitions already exist. Testonaut handles this by scanning the target repository before scenario authoring.

What the scanner reads
The step library scanner walks the repository and reads .feature files, ignoring generated or irrelevant folders (node_modules, .git, .agents, dist, out, build, coverage, bin, obj, target). It collects:
| Collected item | Purpose |
|---|---|
| Unique Given/When/Then step vocabulary | Tells the LLM which exact step phrasings already exist and should be reused. |
| Representative raw examples | Keeps examples of how the team writes the step in practice. |
| Occurrence counts | Lets the most common steps rise to the top. |
| Existing scenario titles | Prevents writing a scenario that already exists in the repo. |
| Feature file count and total step count | Gives a useful audit summary in the run output. |
Step normalization
The scanner normalizes value-like literals so structurally identical steps collapse into one reusable template:
| Raw examples | Normalized step |
|---|---|
the amount is "300 EUR" and the amount is "50 EUR" | the amount is "<param>" |
I select 12 months and I select 24 months | I select <number> months |
the status is <status> | the status is <param> |
This is what lets the prompt say "reuse this step shape, substituting the right data," instead of treating every literal value as a separate step.
How step reuse reaches the LLM
When a step library exists, the Gherkin prompt includes a dedicated section, grouped by keyword (Given / When / Then), instructing the model to reuse those exact phrasings and only write a new step when none matches. This is not a soft hint hidden in a paragraph — it is an explicit authoring constraint, because avoiding duplicate Cucumber glue code is a first-class design requirement.
Existing test de-duplication

Repository scenario de-duplication
While scanning .feature files, Testonaut also collects scenario and scenario-outline titles. Those titles are placed in the prompt with the instruction: do not author a scenario that means the same thing; if an acceptance criterion is already covered by an existing repo scenario, put that AC id in acsCoveredByExisting instead of writing a duplicate scenario.
Linked Xray test de-duplication
The Researcher includes already-linked Xray tests in ContextPack.xrayTestCases, and Phase 2 adds them to the existing-test prompt section. During Xray upload, Testonaut performs another safety check: it normalizes scenario titles and skips tests whose title already exists among linked tests or among scenarios created in the same run — catching case, punctuation, or unicode differences that would otherwise create near-duplicates.
Two-pass design flow
The Test Architect uses multiple bounded design passes rather than one big prompt.

Pass 1: acceptance criteria extraction
The first LLM pass extracts atomic acceptance criteria from the ContextPack. Each AC is assigned an id such as AC-1, written in business language, and can point back to its source — the description, a comment, or a Confluence page. After AC extraction, the evidence graph is rebuilt so requirement nodes appear in the graph.
Pass 2: scenario authoring
| Output mode | Result | Xray test type |
|---|---|---|
gherkin | Given/When/Then scenarios written as .feature files | Cucumber |
plain-english | Action / expected-result manual test cases | Manual |
In Gherkin mode, the author receives the existing repository step vocabulary and is instructed to reuse it. In plain-English mode, step-library reuse is not relevant, but existing test de-duplication still matters.
Scenario contract
Each generated scenario carries structured fields used by gates, reporting, and implementation:
| Field | Purpose |
|---|---|
title | Business-readable scenario title. |
feature | Feature file grouping. |
tags | Feature-area tags only, such as @login or @checkout. |
acIds | Acceptance criteria covered by the scenario. |
drIds | Derived requirements covered by the scenario. |
polarity | positive, negative, or boundary. |
risk | high, medium, or low. |
readiness | ready or needs-clarification. |
objective | What the scenario verifies. |
preconditions | Setup assumptions. |
steps | Gherkin steps or manual action/expected-result steps. |
sourceEvidence | Traceability back to description, comments, Confluence, attachments, or related tickets. |
openQuestions | Scenario-specific questions for the product/team. |
rationale | Why this scenario exists. |
Tag hygiene
Tags are deliberately kept simple — the agent does not use tags for data that belongs in structured fields:
| Do | Do not |
|---|---|
@login, @checkout, @instalments | @AC-1, @high, @positive, @story-ABC-123 |
The Jira key is added at the feature level automatically. @smoke is derived from risk: high. AC ids, risk, and polarity live in structured fields, which keeps coverage checks machine-readable.
Coverage gates
The Coverage Auditor checks the generated design before it is accepted:
| Gate | What it enforces | Behavior |
|---|---|---|
| AC coverage | Every AC must be covered by a generated scenario or by acsCoveredByExisting. | Required by default. One bounded retry fills missing ACs. |
| Risk / edge coverage | High-risk ACs or derived requirements should have at least one negative or boundary scenario. | Defaults to warn. Can be required, warn, or off. |
| Existing coverage | ACs covered by existing repo scenarios or linked Xray tests count as covered. | Prevents forced duplicates just to satisfy a gate. |
If AC coverage fails and the gate is required, the run stops with a clear error. If the gate is warn, the gap is recorded as an open question and warning.
Derived requirements and adversarial critique
The literal acceptance criteria are the floor, not always the whole test strategy. Phase 2 can also mine implied requirements from the full context — missing but evidence-backed behaviors such as:
- error and rejection paths;
- boundary values;
- missing or maximal data;
- permissions and security expectations;
- state transitions and concurrency;
- notable usability or performance constraints.
After the initial scenario design, an adversarial critique pass asks: "what did this design miss?" It can add genuinely missing scenarios, record coverage gaps, or raise open questions. It is bounded, evidence-grounded, and not allowed to duplicate already drafted scenarios.
Xray upload
When upload is enabled, Testonaut applies the TestDesignPack to Xray:

- Gherkin scenarios become Xray Cucumber tests; plain-English scenarios become Xray Manual tests.
- Tests are linked back to the story using the configured or resolved Jira link type.
- Required Jira fields can be inherited or supplied through
xray.testFields/--test-fields. - Titles are normalized to avoid duplicate creation across reruns.
- Upload can run as
--dry-runor require--yes/ policy approval.
Failure behavior and guardrails
| Situation | Behavior |
|---|---|
| No LLM is configured | Phase 1 context is still written; Test Architect is skipped. |
| No repository is resolved | Design still runs, but without step reuse; the CLI explains how to enable it. |
| Step library scan finds no feature files | Design still runs; no reuse vocabulary is injected. |
| LLM returns non-JSON or malformed JSON | Run fails with a clear schema/parsing error. |
| Scenario references unknown AC/DR ids | Unknown ids are dropped and warnings are recorded. |
| AC coverage misses requirements | One bounded retry; then warn or fail depending on the gate. |
| Risk coverage misses negative/boundary cases | Warn or fail depending on the gate. |
| Xray upload sees an existing title | Scenario is skipped as existing rather than duplicated. |
| Xray upload partially fails | Per-test result and warnings are recorded in the application result. |
Configuration knobs
| Setting / flag | Purpose |
|---|---|
--repo <path> | Explicit local repository used for step reuse and repo skill overrides. |
TESTONAUT_REPO_ROOTS | JSON map of repository name to local checkout path for dev-section resolution. |
testDesign.outputMode | gherkin or plain-english. |
--gate / policy.gates.acCoverage | AC coverage enforcement: required, warn, or off. |
--derive-requirements / policy.design.deriveRequirements | Enables implied requirement mining. |
--adversarial-critique / policy.design.adversarialCritique | Enables the critique pass. |
--risk-coverage / policy.gates.riskCoverage | Risk/edge gate: required, warn, or off. |
--test-fields / xray.testFields | Extra Jira fields for created Xray Test issues. |
--reporter | Sets Reporter on created Test issues, useful for Jira automation attribution. |
--dry-run | Preview Xray upload without mutations. |
--yes | Confirms upload when human review is required. |
Why this phase matters
