14 · Dashboard observability
The reactive surface. An invocation submitted from the CLI or SDK should appear in the dashboard's Invocations view, transition through states, and report its outcome — with no page refresh.
Exercises
- The dashboard's long-poll loop against
GET /v1/admin/invocations. - Cursor-based change detection: the response carries a
cursorand the next request holds until the server's cursor moves past it. - CORS for cross-origin browser fetches (Netlify origin → Heroku control plane).
Requires
- The control plane up, and the dashboard either running locally or the
hosted one at
demo.lakeshore.dreamlake.ai. - At least one daemon registered and draining the queue you submit to,
or the row will sit in
queuedforever. - Admin auth —
/v1/admin/*is gated onLAKESHORE_ADMIN_TOKEN, or passes freely in dev open mode when that variable is unset.
GET /v1/admin/invocations resolves the default namespace and reads
its invocations. There is no namespace query parameter. Submitting into
some other namespace produces a row the dashboard's Invocations view will
not show.
Verifies
Submit → live state transitions visible in the browser without a manual refresh.
Run
In one terminal, submit:
In the browser, open the dashboard and go to Invocations.
Expected output
A new row appears, moves queued → running → succeeded, and settles
with a result preview. The delay before it appears is bounded by the
long-poll window, not by a fixed refresh interval.
The long-poll contract
| Query param | Default | Cap |
|---|---|---|
cursor | 0 | — |
timeout_s | 30 | 60 |
limit | 100 | 500 |
The request blocks until the server's adminCursor passes the supplied
cursor, or the timeout expires. The response is
{ invocations, cursor }; feed that cursor back into the next
request. Rows are ordered newest-submitted first, and each carries id,
queueName, functionQualname, state, workerId, the three
timestamps, and progress.
queueName is read off runConfig.queue — Phase A.5 removed
Invocation.queueId, so there is no join and no foreign key. Rows with
nothing there render as default.
If it fails
| Symptom | Likely cause |
|---|---|
| The row never appears | Submitted into a non-default namespace — see the callout above — or into a namespace the dashboard account is not pointed at. |
The row appears but stays queued | Nothing is draining the queue. Check lakeshore daemon list and the daemon's queues column. |
401 on /v1/admin/invocations | The control plane has LAKESHORE_ADMIN_TOKEN set and the dashboard is not sending it. |
| CORS error in the browser console | The control plane registers @fastify/cors with origin: true (reflect any origin), so a CORS failure usually means the request never reached it — check the URL and TLS first. |
| The row appears but never updates | The long-poll hung. Look for the /v1/admin/invocations?cursor=… request in the Network panel; a request that returns without the cursor advancing is the tell. |
Status
Manual.