Epic 3 — Run Triggering & Configuration

Covers manual run submission, depth_level / target_framework / branch parameter selection, client-side idempotency key generation and retry replay, optimistic run-row insertion, 429 rate-limit rejection with retry-after display, and the pre-flight quota banner.

Personas: BU (primary trigger) OP

Shared modules: OptimisticMutationHelper CorrelationChip EnvProvenance

Story 3.1 — Submit a Run

As a
BU
I want
to trigger a new pipeline run for a project with configurable parameters
So that
AMTP executes against the branch and depth I specify
Scenario: Successful run submission
Giventhe user is on the run-trigger form for an active project; the project has no active run Whenthe user selects depth_level, target_framework, and branch and clicks Run ThenPOST /runs is issued with { project_id, depth_level, target_framework, branch, x_idempotency_key } Andthe user is navigated to the new run's timeline page (/runs/{run_id})
Scenario: Branch list loads and is searchable
Giventhe run-trigger form renders WhenGET /projects/{project_id}/branches resolves Thena searchable branch picker is rendered; the project's base_branch is pre-selected; typing filters the list client-side
Mutation addendum — Optimistic run-row insertion + rollback:

Before issuing POST /runs, the UI generates a fresh x-idempotency-key (UUID v4), clones the runs list into prior_state, and inserts an optimistic run row tagged Submitting… at the top of the list. On 4xx / 5xx / network-loss the row is removed and prior_state is fully restored; the CorrelationChip surfaces the failure. On 409 with error pr_lock, the failure cause displayed is pr_lock contention (cross-link to Epic 7).

Endpoint / DBPurpose
POST /runsCreate run; body includes x-idempotency-key
GET /projects/{project_id}/branchesBranch list for picker
DB runs.depth_level, runs.branch_nameWritten on creation

Story 3.2 — Client-Side Idempotency Key

As a
BU
I want
a client-generated idempotency key sent with every run-trigger request
So that
network retries never create duplicate runs
Scenario: Fresh key generated per submission attempt
Giventhe user opens the run-trigger form Whenthe form mounts Thena UUID v4 x-idempotency-key is generated and persisted in component state for this attempt Andthe same key is reused for all retries of this specific submit action Anda new key is generated only when the user explicitly resets or re-opens the form
Scenario: Duplicate submission detected by server — idempotent 200
Givena prior POST /runs with key K succeeded and the UI retries with the same key K (e.g. after a network timeout) Whenthe server returns 200 with the existing run_id Thenthe UI navigates to the existing run timeline without creating a duplicate run row

Story 3.3 — Rate-Limit Rejection Display

As a
BU
I want
to see a clear message when my run trigger is rejected by the rate limiter
So that
I know how long to wait before retrying rather than assuming a system failure
Scenario: 429 rate-limit response displayed
Giventhe user's sliding-window run quota (Valkey key amtp:rl:user:{userId}:runs) is exhausted WhenPOST /runs returns HTTP 429 Thenthe optimistic row is rolled back; a non-dismissible banner is displayed showing the Retry-After countdown and CorrelationChip Andthe Run button is disabled with an accessible tooltip until the countdown expires
Scenario: 409 concurrency limit — per-repository
Giventhe repository's concurrency limit (amtp:rl:repo:{repo}:concurrency) is at capacity WhenPOST /runs returns 409 with error concurrency_limit Thenthe optimistic row is rolled back; an inline message reads This repository is at maximum concurrency. Wait for an active run to complete and retry. with CorrelationChip

Story 3.4 — Pre-Flight Quota Banner

As a
BU
I want
to see a warning before submitting when I am close to my rate limit
So that
I can plan my submissions before hitting a hard 429
Scenario: Quota warning banner shown when ≤ 10 % capacity remains
GivenGET /quota/runs returns remaining ≤ 10% of the sliding-window limit Whenthe run-trigger form renders Thenan amber pre-flight warning reads: You are close to your run limit. N runs remaining in the current window (resets at <time>). Andthe Run button remains active; the banner is informational only
Scenario: Quota exhausted — form submit button disabled pre-flight
GivenGET /quota/runs returns remaining: 0 Thena red pre-flight banner reads: Quota exhausted — next window opens in <countdown>.; the Run button is disabled before the form is submitted
Endpoint / DBPurpose
GET /quota/runsCurrent quota state for pre-flight check
DB Valkey amtp:rl:user:{userId}:runsSliding-window counter