Skip to content

feat: realtime test status with polling backstop#27

Merged
riglar merged 1 commit into
devfrom
feat/realtime-results
Jun 22, 2026
Merged

feat: realtime test status with polling backstop#27
riglar merged 1 commit into
devfrom
feat/realtime-results

Conversation

@riglar

@riglar riglar commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What & why

The CLI learned test-run status only by HTTP polling (GET /results/{uploadId} every 10s). The backend already writes status to the Postgres results table, that table is in the supabase_realtime publication, and the frontend already consumes it live. This PR gives logged-in users near-instant status by reusing that same channel, while keeping polling as the resilience backstop.

Approach

Realtime is a latency optimisation layered over the existing poll loop, not a rewrite. A realtime change "pokes" the loop to fetch immediately, so all existing render / terminal-state / artifact-download logic is reused unchanged. If realtime can't connect (network blocks WebSockets, or the user is on an api-key), the loop just keeps polling.

  • AuthContext now carries accessToken + env for bearer (logged-in) sessions, so the realtime socket can authenticate under RLS. No DB migration needed — we only read the new row (status, test_upload_id), which Postgres always ships on INSERT/UPDATE.
  • RealtimeResultsGateway (new) — subscribes to postgres_changes on results filtered by org_id, setAuths the JWT, fires onChange when a row for this upload changes. Construction never throws; any failure degrades silently to pure polling.
  • Backstop cadence — 60s for bearer users (realtime carries the fast path), 20s for api-key users (no realtime). The inter-poll wait is interruptible and latches pokes that arrive mid-fetch, so events are never silently dropped.
  • api-key nudge — a dim dcd login tip, suppressed in CI / --json / --quiet via a new dependency-free isCI() helper.

Known limitations (documented in code)

  • A run longer than the access-token lifetime may drop the realtime socket; the bearer poll header is also fixed at resolve time. The 60s backstop is the resilience mechanism — revisit mid-run token refresh if it bites.
  • api-key invocations have no Supabase JWT, so they can't use realtime under RLS — by design, they stay on polling.

Verification

  • pnpm typecheck — clean
  • pnpm lint — 0 errors
  • pnpm test147 passing (142 + 5 new isCI unit tests)
  • Integration tests unaffected: none exercise the poll-to-completion path, and the nudge auto-suppresses under exec (non-TTY).

Manual (not yet run against a live env): logged-in run with --debug should show the channel SUBSCRIBED and status updating between the 60s polls; api-key run should show 20s polling + the tip, with the tip gone under CI=1.

🤖 Generated with Claude Code

Logged-in (bearer) users now get near-instant run status via a Supabase
Realtime subscription on the `results` table, layered over the existing
poll loop as a latency optimisation rather than a rewrite: a realtime
change "pokes" the loop to fetch immediately, reusing all existing
render/terminal/artifact logic.

- AuthContext exposes accessToken + env for bearer sessions so realtime
  can authenticate the socket under RLS (no DB migration needed — we only
  read the `new` row).
- RealtimeResultsGateway: subscribes to postgres_changes on `results`
  filtered by org_id; any failure degrades silently to pure polling.
- Backstop cadence: 60s for bearer (realtime carries the fast path),
  20s for api-key users (no realtime). Inter-poll wait is interruptible
  and latches pokes that land mid-fetch so events are never dropped.
- api-key users get a dim `dcd login` tip, suppressed in CI / json / quiet.
- New isCI() helper + unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jun 22, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@riglar riglar merged commit 1284cb3 into dev Jun 22, 2026
3 checks passed
@riglar riglar deleted the feat/realtime-results branch June 24, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant