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.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.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
- Assemble. A 60-second reconciler builds a generation — a throwaway
uat/<label>-<codename>-<MMDD>branch offmain— 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). - 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.
- 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.
- 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.
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 oneuat/… 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
mainto undo one. Clicking merge again skips what already landed and finishes the rest.
Live UAT stacks
Each generation can serve a live dashboard atuat-<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 reachesmain until you say so.
Engineering reference
The full model, modules, reconciler, API, and promotion semantics live in
docs/UAT-BATCH-TRAINS.md.