Overview
The web console is The Test Cabinet’s runner/reporter GUI running in a plain browser. It is the same console as the Tauri app — sign in, configure and launch runs, watch their live event stream, return to any run still in progress — and kill one from its live monitor — be notified when one completes, read specs, review finished runs, and publish them — but delivered as a static web app instead of a desktop binary. (A produced run’s record is stored on the backend by the driver when the run finishes, so the console has no separate push step.) Both consoles enqueue runs at the backend’s run queue and watch them; neither runs a test case itself.
It shares its entire UI with the Tauri app through the
UI library: both mount the same GalleryApp and
differ only in what they connect to. The shared app gates its run-execution
surface on a canExecute flag, which both consoles set; the static site leaves
it off.
Two kinds of connection
Section titled “Two kinds of connection”The console talks to two distinct services, mirroring Runners and Reporters:
- A single backend — the source of truth for the test case catalog, definitions, and published results. The console resolves the catalog and reads published data from here, over the backend HTTP API. It is never asked to a worker.
- The backend also owns the run queue — a launched run is enqueued at the
backend over the backend HTTP API, where a
dispatcher claims it and creates a per-run
driver
Job; the driver’s live events stream back through the backend to the console. The backend also proxies account register/login to the auth service and forwards the signed-in account’s bearer token to the backend when the console reviews or publishes, so the console authenticates through the same worker it runs on.
The web console and the Tauri app are now wired the
same way: both enqueue runs at a single backend over the same HTTP transport
(@test-cabinet/ui/transport) and watch them. The desktop app additionally runs
the adversarial arena locally, in-process; that
is the only execution either console performs on its own machine.
One backend, consistent workers
Section titled “One backend, consistent workers”There can be several backend instances (for example staging and production), but
the console points at exactly one at a time. Because every worker is itself
bound to a backend (TCAB_BACKEND_URL), the console checks each connected worker
against the active backend and flags a worker bound to a different one — so it
can’t ask a worker to run a test case that worker’s backend can’t resolve.
Launching on a mismatched worker is disabled.
The worker reports the backend it is bound to from its GET /healthz probe (as
backendUrl), which the console compares against the backend it is itself
pointed at. A worker that can’t be reached or doesn’t report a backend is shown
as unverified rather than blocked, so an unreachable health probe degrades
gracefully instead of locking the worker out.
Bounded run loading
Section titled “Bounded run loading”The console does not drain the whole cabinet into memory. Its run and model
list pages are server-paged: each page issues a
GET /runs?fields=summary query in the
numbered-offset mode (offset + limit), driving the numbered pager off the
returned total. Search, the page-scoped filter (a model id on the model-runs
page, a case slug elsewhere), and column-header sort are sent as query params, so
filtering and sorting happen in the backend, not client-side; changing any of them
re-queries and resets to page 0, and produced/in-progress runs the worker holds
locally are pinned to page 0. The home page fetches a recent window, and the
case-scoped leaderboard and metrics views fetch one bounded, case-scoped summary
set. Only a run’s detail page loads that run’s full
record (and its reviews),
lazily, one run at a time. Lightweight
RunSummary cards back
every list, card, leaderboard, and metric.
Deployment
Section titled “Deployment”Like the public site, the web console is a fully
static bundle (vite build). Unlike the site, it is an operator tool, not a
public gallery: it reads from and writes to the private backend and drives
private workers, so it is served on the same private network as the services it
talks to (see Authentication),
not deployed to the public internet. In a cluster deployment that bundle is the
in-cluster tcab-web workload, reached over the VPN at a private hostname through
the internal ingress — never a public
FQDN.
Status
Section titled “Status”apps/web is a thin host: it supplies the HTTP BackendClient and
WorkerClient transports and the connection state (backend selection and worker
add/remove/select), then mounts the shared GalleryApp. The whole console UI —
the routed gallery plus the run-execution screens — comes from the
UI library, so it is the same app the desktop renders.
It runs against the now-implemented backend
contract: the backend serves the catalog and published runs, owns the run queue
that the dispatcher drains into per-run
driver Jobs, and exposes its run-enqueue,
produced-run listing, recorded-event, notification, auth-proxy, and
review/publish endpoints. Where a host can’t
provide a piece of data — for example a worker that returns no recorded events
for an older run — the shared UI degrades gracefully rather than erroring.