>_ Analyst Engineering

The Requirements to UAT Pipeline: One Repository From Workshop to Sign-Off

Written by Ahmed at Analyst Engineering, a Senior Technical Business Analyst with 10+ years in banking and payments delivery.

Cover for a guide to building a requirements to UAT pipeline, from workshop transcript to signed test results.

Key takeaways

  • Requirements work fails at the handoffs, not inside the documents. Every time a requirement is retyped into a new tool it loses an identifier, and coverage becomes an opinion instead of a query.
  • A requirements pipeline is defined by one rule: every stage reads a machine-readable artifact produced by the previous stage, and never a human retelling of it.
  • Three formats carry the whole chain. Requirements as YAML with stable identifiers, scenarios as Gherkin tagged with those identifiers, and results as JUnit XML tagged the same way. Everything else is rendering.
  • The coverage gate is the piece that changes behaviour. When a build fails because REQ-014 has no scenario, nobody has to chase coverage in a meeting again.
  • AI is the labour in this pipeline, not the authority. It drafts every artifact and reviews every artifact, and a named human approves each one before it moves to the next stage.

A requirements pipeline is a chain in which every stage reads the machine-readable output of the previous stage rather than a human retelling of it. A workshop transcript becomes requirement candidates, candidates become identified requirements in YAML, requirements become use cases, use cases become UAT scenarios in Gherkin, and scenarios become test results tagged with the original requirement id. Traceability stops being a spreadsheet and becomes a query.

Requirements work almost never fails inside a document. It fails at the handoffs. The workshop produced a good decision that nobody wrote down in the same words. The business requirement was accurate and the functional requirement that refined it quietly changed a threshold. The test analyst read the functional spec, built a suite, and covered eleven of the fourteen rules because three of them were in a paragraph rather than a table. Then UAT found the gap in week nine, which is the most expensive week to find anything.

Every one of those failures has the same shape. A requirement was retyped into a new tool and lost its identifier on the way. This article is the system that removes the retyping. The rest of the series builds each stage properly: elicitation with an AI note taker, requirements as code, connecting Jira, Confluence, Xray, and Datadog over MCP, analyzing the diagrams you were handed, the blind spot review, use cases and UAT scenarios, and test strategy through to execution. If you want the document templates that sit at each stage, they are in The BA Deliverables Template Pack.

What are the eight stages, and what is the artifact at each one?

The pipeline is only a pipeline because each row’s output is the next row’s input, in a format a script can read.

StageInputArtifactFormatGate before it moves on
1. ElicitationMeeting, transcript, existing systemDecisions, actions, requirement candidatesMarkdownEvery candidate has a named source
2. Business requirementsCandidates plus strategyBRD, each requirement identifiedYAML plus rendered MarkdownSchema valid, every REQ has an owner
3. Functional requirementsBRD plus system artifactsFRD, each rule testableYAMLEvery FR refines a REQ that exists
4. Use casesFRD plus actorsMain, alternate, exception flowsYAMLEvery FR appears in at least one flow
5. Blind spot reviewEverything aboveGap register, new requirementsYAMLNine lenses run, each gap closed or accepted
6. Test conditionsFRD plus gap registerConditions with risk ratingYAMLEvery FR has at least one condition
7. UAT scenariosUse cases plus conditionsGherkin feature filesfeature filesEvery scenario tagged with a REQ id
8. ExecutionFeature files plus environmentsRun results, evidence, sign-off packJUnit XML plus MarkdownCoverage gate green, results signed

Read the last column as the real content of the pipeline. Anyone can produce eight documents. The value is that stage five cannot start until stage four passed its gate, and that the gate is a script rather than a review meeting where three people say “looks fine to me”.

What does the repository look like?

One folder per project, in git, next to nothing else. This is the entire structure:

payments-iso-migration/
  context/
    system.md            # the context pack: actors, systems, vocabulary
    house-style.md       # how we write requirements here
    glossary.yaml        # terms with one agreed definition each
  elicitation/
    2026-09-08-kickoff.md
    2026-09-15-pacs008-workshop.md
  requirements/
    business.yaml        # REQ-001 ..
    functional.yaml      # FR-001 .. each refines a REQ
    use-cases.yaml       # UC-001 .. each realises FRs
    gaps.yaml            # GAP-001 .. from the blind spot review
  tests/
    conditions.yaml      # TC-001 .. each covers FRs
    features/
      payment-initiation.feature
      rejection-handling.feature
    strategy.md
  scripts/
    validate.py          # schema and reference integrity
    coverage.py          # the traceability matrix and the gate
    render.py            # YAML to Markdown for humans
    publish.py           # Confluence pages, Jira issues, Xray tests
  .github/workflows/
    requirements.yml     # runs validate, coverage, render on every push

Two design decisions in there matter more than the rest.

The context/ folder exists so nobody writes a prompt from memory. Every AI step in this pipeline starts by loading system.md, house-style.md, and glossary.yaml. That is what stops a model from inventing an actor called “Payment Service” when your architecture calls it the Processor, and what stops the same field being called debtorAccount in one requirement and payer account in the next. The general technique is context engineering, and it is the single highest leverage file in the repository.

Everything downstream of business.yaml is derived. If you find yourself editing a rendered Markdown document, the pipeline has broken. Fix the YAML and regenerate.

The three formats that carry everything

You do not need a requirements management tool. You need three formats and one shared identifier.

Requirements as YAML. A requirement is a record with an id, a statement, a rationale, an owner, a priority, and acceptance criteria. Structured, so a script can count them, diff them, and check that every functional requirement points at a business requirement that exists. This is the subject of requirements as code.

- id: REQ-014
  title: Reject payments above the customer daily limit
  statement: >
    The platform must reject a payment instruction when it would take the
    originating customer above their agreed daily limit for that currency.
  rationale: Regulatory exposure and credit risk control.
  owner: Head of Payments Operations
  priority: must
  source: 2026-09-15-pacs008-workshop.md#decision-4
  acceptance:
    - A payment that would breach the limit is rejected with reason code AM04.
    - The customer receives the rejection within 5 seconds of submission.
    - The attempt is recorded in the limit breach audit log.

Scenarios as Gherkin, tagged with the requirement id. Gherkin is readable by business users and parseable by machines at the same time, which is the only reason it survived. The tag is what makes the whole pipeline work.

@REQ-014 @FR-031 @uat @priority-high
Scenario: Payment rejected when it breaches the daily limit
  Given customer NP-4471 has a daily EUR limit of 50,000
  And they have already sent 48,000 EUR today
  When they submit a payment of 5,000 EUR
  Then the payment is rejected with reason code AM04
  And the rejection is returned within 5 seconds
  And a limit breach entry appears in the audit log

Results as JUnit XML, carrying the tags through. Every runner worth using emits JUnit XML, and every CI system reads it. Because the scenario name and tags survive into the result file, the execution report can be joined back to business.yaml by requirement id. That join is the traceability matrix, and it is regenerated on every run rather than maintained by hand. The requirements traceability matrix article covers what the matrix is for; this pipeline is how you stop maintaining it manually.

The four gates that make it real

A gate is a script that exits non-zero. That is the whole mechanism, and it is why this works when a checklist does not.

# scripts/coverage.py (the part that matters)
import sys, yaml, glob, re

reqs = {r["id"] for r in yaml.safe_load(open("requirements/business.yaml"))}
frs  = yaml.safe_load(open("requirements/functional.yaml"))

# Gate 1: every functional requirement refines a business requirement that exists
dangling = [f["id"] for f in frs if f["refines"] not in reqs]

# Gate 2: every business requirement is refined by at least one functional requirement
refined = {f["refines"] for f in frs}
unrefined = sorted(reqs - refined)

# Gate 3: every requirement is tagged by at least one scenario
tagged = set()
for path in glob.glob("tests/features/**/*.feature", recursive=True):
    tagged |= set(re.findall(r"@(REQ-\d+)", open(path, encoding="utf-8").read()))
uncovered = sorted(reqs - tagged)

for label, items in [("dangling FR", dangling), ("unrefined REQ", unrefined),
                     ("uncovered REQ", uncovered)]:
    for i in items:
        print(f"FAIL {label}: {i}")

sys.exit(1 if dangling or unrefined or uncovered else 0)

Forty lines, and it replaces the recurring meeting where somebody asks whether the test suite covers the new rules. The fourth gate runs after execution: every requirement marked must needs a passing result in the current run before the sign-off pack can be generated. That one belongs to the execution pipeline.

Wire all four into a workflow file and they run on every push:

# .github/workflows/requirements.yml
name: requirements
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - run: pip install pyyaml jsonschema
      - run: python scripts/validate.py
      - run: python scripts/coverage.py
      - run: python scripts/render.py --out build/
      - uses: actions/upload-artifact@v4
        with: { name: requirements-pack, path: build/ }

Now a pull request that adds a requirement without a scenario turns red, and the reviewer sees exactly which id is uncovered. Nobody negotiates with a red build the way they negotiate with a checklist.

Where AI sits, stage by stage

The honest division of labour. AI is the typist and the second reader. It is never the approver.

StageWhat AI draftsWhat you decide
ElicitationDecisions, actions, candidates, contradictions in the transcriptWhich candidates are in scope, who owns each
Business requirementsStatement, rationale, acceptance criteria from a candidatePriority, correctness of the business rule
Functional requirementsRefinement into testable rules against the contractWhether the rule matches the system that exists
Use casesAlternate and exception flows you did not think ofWhich exceptions the business accepts
Blind spot reviewThe nine adversarial passes, exhaustivelyWhich gaps are real and which are noise
Test conditionsConditions from each rule, including boundariesRisk rating and depth of coverage
UAT scenariosGherkin from use cases, in business languageWhether a business user would recognise it
ExecutionFailure triage, defect summaries, the run reportPass, fail, and the go or no-go call

The right column is the job. Anyone who thinks AI replaces the analyst has only ever looked at the left column. The reason the pipeline is worth building is that the left column used to consume eighty percent of the week, and it is also the column where machines are genuinely better than tired humans at 17:30 on a Thursday.

The guardrails are not optional. Transcripts contain names, payloads contain customer data, and neither belongs in a prompt without classification. Everything in AI guardrails for analysts applies here, and the pipeline makes compliance easier rather than harder because the redaction step is a script that runs the same way every time.

The build order, four weeks of evenings

Do not build all eight stages before using any of them. Build the spine first and widen it.

  1. Week one. Create the repo, write context/system.md, and move your current requirements into business.yaml by hand. This is the boring week and it is the one that pays.
  2. Week two. Write validate.py and coverage.py, and wire the workflow. Accept that the first run fails loudly; that failure list is your actual coverage, probably for the first time.
  3. Week three. Add render.py and the publish step so Confluence, Jira, and Xray read the same content without you copying anything.
  4. Week four. Add the Gherkin layer and the execution join, then run the blind spot review on the whole set and watch it find things.

By week four you will have a traceability matrix that regenerates on every push, which is the artifact every audit asks for and almost no team can produce on demand.

What this does not fix

Being clear about the limits keeps the thing credible.

  • It does not make stakeholders agree. A pipeline transports decisions; it does not produce them. The workshop still has to happen.
  • It does not replace domain knowledge. The pipeline will happily carry a wrong business rule from stage one to stage eight, with perfect traceability.
  • It does not work with an unwilling team. If the developers ignore the rendered spec and build from a Slack thread, the traceability is decorative.
  • It is not a substitute for testing judgement. Full coverage of the requirements you wrote says nothing about the requirement you never thought of, which is exactly why the blind spot review is a stage rather than a nice idea.

The takeaway

The difference between a folder of documents and a pipeline is that a pipeline has gates. Give every requirement an identifier on the day it is born, keep it in a structured file, carry that identifier into every downstream artifact, and let a script fail the build when the chain breaks. AI then does the drafting at every stage, which is what makes the extra rigour affordable rather than aspirational.

Start with requirements as code, because nothing else in the chain works until the requirement has a stable id. Then read the blind spot review and run it against a spec you have already signed off; it will find something, and that finding is usually what convinces the team. For the templates behind each stage, see The BA Deliverables Template Pack, or browse everything at The Tech BA Toolkit.

Ahmed is a Senior Technical Business Analyst with 10+ years in banking and payments. He builds practical guides and tools for analysts at The Tech BA Toolkit.

Tags: Business Analysis, Requirements Engineering, AI, UAT, Traceability

About the author

Analyst Engineering is written by Ahmed, a Senior Technical Business Analyst with 10+ years of banking and payments delivery experience: ISO 20022 and SWIFT messaging, payments API integration, Kafka event validation, and production support. Every article comes from real delivery work, and each one is reviewed and updated as tools and standards change.

Free account

Practice on the Labs, keep your progress

A free account, no password: an email link signs you in. It saves your steps and self-assessments on the Labs, shows your missions on a dashboard, unlocks the solutions, and, if you tick the box, sends you new missions and articles when they ship.

Your email is used to sign you in. Nothing else, unless you ask. Privacy.