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
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
GET /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
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 / DB | Purpose |
|---|---|
POST /runs | Create run; body includes x-idempotency-key |
GET /projects/{project_id}/branches | Branch list for picker |
DB runs.depth_level, runs.branch_name | Written 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
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
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
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
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
GET /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
GET /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 / DB | Purpose |
|---|---|
GET /quota/runs | Current quota state for pre-flight check |
DB Valkey amtp:rl:user:{userId}:runs | Sliding-window counter |