Hackorda Docs
Flows

F 07 Test Run

Status: 🟢 ready to test Owner: Adilet Last updated: 2026-05-08 Last verified on production:

Goal

A tester opens an active cycle, clicks "Start run" to capture their environment, files issues during the run, drops a session recording or log into the run pack, then clicks "End run" to mark it complete (which fires the AI run summary).

Actors

  • Primary — Tester (cycle member, role tester or lead)
  • Secondary — AI run-summary agent (fire-and-forget)

Preconditions

  • Cycle is active (F-05)
  • Tester is a member (testers row exists)
  • Tester is signed in

Trigger

Tester opens /app/test-cycles/:id, scrolls to "My runs", clicks "Start run".

Happy path — start run

#ActorUI surfaceActionAPI callDB writesSide effectsSuggested event
1Testercycle detail "My runs"Click "Start run"POST /api/test-cycles/:id/runsINSERT INTO test_runs (status=in_progress, environment auto-captured from UA / OS / browser / screen)run.started
2Frontend"My runs" listNew row at top, status in_progress

Happy path — file issues during the run

See F-08. Each issue filed during the run gets run_id set automatically (the cycle page knows which run is open).

Happy path — attach run pack media

#ActorUI surfaceActionAPI callDB writesSide effectsSuggested event
1TesterRunPackPanel (expanded)Drop screen recording / HAR / console.logPOST /api/test-cycles/:id/attachments body { targetType: 'test_run', targetId: runId }INSERT INTO attachmentsDO Spaces uploadattachment.uploaded
2Frontendrun pack tile galleryTile appears

Happy path — complete run

#ActorUI surfaceActionAPI callDB writesSide effectsSuggested event
1Testerrun rowClick "End run"PATCH /api/test-cycles/:id/runs/:runId body { status: 'completed', notes: '…' }UPDATE test_runs SET status='completed', ended_at = NOW(), notes = …AI run-summary agent fires (fire-and-forget)run.completed
2AIbackgroundReads run + issues filed during run(none, just Anthropic API call)INSERT INTO ai_runs, UPDATE test_runs SET ai_summary = …ai.run_summary_completed (or _failed)

Acceptance criteria

  • AC-1 — Given the tester clicks "Start run", when the POST returns, then test_runs.environment is populated from the request headers (UA + browser + OS + screen + locale).
  • AC-2 — Given an open run exists, when the tester files an issue via F-08, then issues.run_id is set to the open run.
  • AC-3 — Given a run is in progress, when the tester completes it, then test_runs.status flips to completed and ended_at is set.
  • AC-4 — Given a run is completed and Anthropic is configured, then within 30s test_runs.ai_summary is populated (or ai_summary_failure_reason if the agent failed).
  • AC-5 — Given a tester abandons a run (closes tab without ending), the run stays in_progress indefinitely. The cron sync-statuses endpoint may auto-abandon stale runs (verify policy).
  • AC-6 — Given a non-member calls POST .../runs, then API returns 403.

Test data / fixtures

  • Baseline seed
  • An active cycle with at least one tester

Negative paths

#ScenarioExpected behavior
N-1Start a second run while one is in progressAllowed (multi-run support); UI shows both
N-2End a run that's already completedAPI 400 "run already completed"
N-3Upload to a run that doesn't belong to the callerAPI 403
N-4Anthropic key missingAgent short-circuits via isAiEnabled(); run completes normally with no summary
N-5Anthropic API error (rate limit, etc.)Logged in ai_runs.failure_reason; run still completes

Manual QA checklist

  • As a tester member, open an active cycle
  • Click "Start run" → row appears in My runs with status In progress
  • Verify the user agent / OS / browser is captured (inspect run detail)
  • Expand the run pack panel; drop a small video file → uploads, tile appears
  • File an issue via "+ File issue" while run is open (F-08) → issue has run_id populated
  • Click "End run" → status flips to Completed, ended_at set
  • Wait 30s, refresh → ai_summary populated (if Anthropic configured)
  • Verify a row exists in ai_runs with kind='run_summary' and status='done'

Automated test outline

test.describe("F-07 test run", () => {
  test("start → end run lifecycle", async ({ page }) => { … });
  test("environment captured", async ({ request }) => { … });
  test("ai summary populates within 30s", async ({ request }) => { … });
  test("non-member 403", async ({ request }) => { … });
});

Code references

  • Pages: src/app/app/test-cycles/[id]/page.tsx (tabs: Brief / Docs / Issues / My runs / Testers)
  • UI: src/components/test-cycles/RunPackPanel.tsx
  • API:
    • src/app/api/test-cycles/[id]/runs/route.ts (GET, POST)
    • src/app/api/test-cycles/[id]/runs/[runId]/route.ts (GET, PATCH)
    • src/app/api/test-cycles/[id]/attachments/route.ts
  • Hooks: src/hooks/test-cycles/runs.ts
  • Lib: src/lib/ai/run-summary.ts
  • Schema: test_runs (incl. environment jsonb, ai_summary, ai_summary_run_id, ai_summary_failure_reason)

Events emitted (proposed)

  • run.started{ cycle_id, run_id, user_id, environment }
  • run.completed{ cycle_id, run_id, duration_seconds, issues_filed }
  • run.abandoned{ cycle_id, run_id, reason }
  • ai.run_summary_completed{ run_id, latency_ms, cost_usd_cents }
  • ai.run_summary_failed{ run_id, failure_reason }

Open questions / known gaps

  • No "abandoned" UI button — only cron/test-cycles/sync-statuses flips stale runs (verify cron is wired). Consider an explicit "Abandon" action.
  • Run summary AI is single-shot — no retry button (intake has retry, summary doesn't yet).
  • No "re-open completed run" path (forces tester to start a fresh run if they want to add more issues afterward).

On this page