> ## Documentation Index
> Fetch the complete documentation index at: https://panopticon-cli.com/llms.txt
> Use this file to discover all available pages before exploring further.

# UAT Batch Trains

> Always one tested batch of every ready feature, ready to merge in one click

# UAT Batch Trains

When agents land merge-ready features faster than you can review and merge them
one at a time, the bottleneck becomes the last-mile UAT. **UAT batch trains** fix
that: Overdeck keeps **one assembled, testable batch of every ready feature**
available at all times, so you can exercise the combined result and then land
exactly what you tested — in a single click.

<Note>
  Batch trains run only while a **Flywheel** run is active and the merge-train flag
  (`flywheel.merge_train_enabled`) is on. They are inert otherwise.
</Note>

## What you see

On the Flywheel page, the **UAT batches** card shows, newest first:

* A **ready batch** — a `uat/<codename>` branch bundling every ready feature,
  with the conflicts between them already resolved. It offers **Open UAT
  frontend** (a live dashboard serving that exact branch), a per-feature **What
  to UAT** checklist, and **Merge batch (N) to main**.
* A batch **assembling** in the background when a new feature becomes ready — the
  current batch stays fully testable until the new one is ready and supersedes it.
* **Held-out** features, with the reason, when a conflict couldn't be resolved
  automatically. Nothing blocks the batch; the held-out feature is retried in a
  later generation.

## How it works

1. **Assemble.** A 60-second reconciler builds a generation — a throwaway
   `uat/<label>-<codename>-<MMDD>` branch off `main` — merging each ready feature
   in order. When two features conflict, a timeboxed assembly agent resolves the
   conflict *inside the batch*; if it can't, that feature is held out (never the
   whole batch).
2. **Accumulate.** New ready features trigger a new, larger generation in the
   background. Generations accumulate — you can test and promote an earlier,
   smaller batch if the newest isn't what you want.
3. **Test.** Click **Open UAT frontend** to exercise the combined branch on a
   real running stack. The checklist pulls each feature's acceptance criteria,
   plus an explicit "verify the touchpoint" item wherever a conflict was resolved.
4. **Promote.** **Merge batch (N) to main** lands exactly the tree you tested —
   conflict resolutions included — in one merge. Each feature then closes out
   through the normal post-merge flow.

Unless the ready feature is held for UAT, a batch assembles only when **two or
more** features are ready. With exactly one, the page reads "1 feature ready —
merges directly; batches assemble when 2+ are ready": a one-member batch is the
PR branch itself and its CI run a duplicate, so that feature merges on its own
(Merge button or `gh pr merge`). A feature held for UAT (its issue's
`hold-for-uat` label, else the project's `auto_merge_default: hold`, else the
global require-UAT setting when the project sets no default) keeps a batch when
it is the only one ready, because that batch is the stack you test on.

Merging a single feature on its own is still available as an escape hatch; doing
so simply restales the live batches and a fresh one reassembles automatically.

## Projects that span several repos

A polyrepo project — one where a single issue's work lands across several member
repositories — gets batch trains too, on the same terms as a single-repo
project. There is no separate setting: the merge-train flag is the only gate.

A batch there spans **one `uat/…` branch per member repo that a ready feature
actually touches**. Repos no feature touches are left alone entirely. The batch
still behaves as one unit:

* **A feature that conflicts anywhere is held out everywhere.** You never test a
  feature that landed in the API repo but not the frontend one — if it can't be
  merged cleanly in every repo it contributes to, it waits for the next batch.
* **Merging is all-or-nothing.** Overdeck first merges every repo locally,
  without publishing anything. Only once all of them succeed does it push. If
  any repo would fail, nothing is published at all and the batch stays exactly
  as it was.
* **An interrupted merge resumes instead of unwinding.** If a push fails after
  some repos already landed, Overdeck tells you which landed and which are still
  pending, and never rewrites a repo's `main` to undo one. Clicking merge again
  skips what already landed and finishes the rest.

The live UAT stack works the same way as for a single-repo project — one stack
per batch, serving all of its repos together.

## Live UAT stacks

Each generation can serve a live dashboard at
`uat-<codename>.overdeck.localhost`, spun on demand from the batch's worktree.
Overdeck runs **at most two UAT stacks at once** (Docker's network pool is
limited) and tears down the oldest when you start a third; promoting or
invalidating a batch always tears its stack down.

## Honest controls

Every action names its exact effect and confirms before anything happens —
"Merge batch (3) to main" lists the three issues and states that it lands the
tree you tested. There is no opaque "Ship batch" button: a batch builds itself,
and nothing reaches `main` until you say so.

<Card title="Engineering reference" icon="book" href="https://github.com/eltmon/overdeck/blob/main/docs/UAT-BATCH-TRAINS.md">
  The full model, modules, reconciler, API, and promotion semantics live in
  `docs/UAT-BATCH-TRAINS.md`.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.