Skip to content

Add a run viewer to the gateway - #50

Closed
jacobprall wants to merge 4 commits into
render-examples:mainfrom
jacobprall:run-viewer
Closed

jacobprall wants to merge 4 commits into
render-examples:mainfrom
jacobprall:run-viewer

Conversation

@jacobprall

Copy link
Copy Markdown
Collaborator

Summary

When FACTORY_VIEWER_PASSWORD is set, the gateway serves a read-only run viewer at /runs, behind HTTP Basic auth (user factory). It lists task runs newest first; expanding one shows its events.

  • No dependencies: a plain HTML/CSS/JS page (app/gateway/viewer/) and two JSON routes, /api/runs (keyset pagination on events.id) and /api/runs/:traceId/events. There's no build step.
  • Security:
    • Every API value is set with textContent, never parsed as HTML.
    • Assets are separate files, so the page runs under a strict Content-Security-Policy (script-src 'self').
    • Responses are no-store and can't be framed.
    • The viewer stays off unless the password is at least 16 characters, and render.yaml generates one.
  • Optional telemetry: without DATABASE_URL, the API answers 503 with "telemetry is off".
  • Brand: styled to Render's brand foundations. It uses the semantic tokens in light and dark, square corners and hairlines, and mono for metadata. Purple is limited to links and the primary action, and green and red only mark done and failed.
  • Migration 0002: adds the two indexes the viewer reads through, and drops the run-claim index nothing queries any more.
  • Telemetry fix: takeover and /factory cancel now record run.finished for the run they stop. Render kills a cancelled run before it can record how it ended, so those runs used to look like they never finished.

Verification

  • npm run check: lint, typecheck, and 107 tests. New tests cover auth (off unless configured; 401 without the password, for the page and the API), pagination and input validation, the "telemetry off" response, and the run.finished event recorded on a stopped run's behalf.
  • Ran the gateway locally against a real factory-db and reviewed the page in a browser, in both themes, with runs expanded into their events.

The gateway serves a read-only viewer at /runs when FACTORY_VIEWER_PASSWORD
is set: a plain HTML/CSS/JS page and two JSON routes, /api/runs and
/api/runs/:traceId/events, behind HTTP Basic auth (user "factory").

- No dependencies or build step. Runs are listed newest first with keyset
  pagination on events.id; a run's events load when it is expanded. Every
  value is set with textContent, and the page is served with a strict CSP.
- Styled to Render's brand foundations: semantic tokens in light and dark,
  square corners and hairlines, mono for metadata, purple only for links
  and the primary action, and green/red only for done/failed.
- Migration 0002 adds the two indexes the viewer reads through and drops
  the unused run-claim index.
- Takeover and /factory cancel record run.finished for the run they stop,
  since Render kills a cancelled run before it can record how it ended.
- render.yaml generates FACTORY_VIEWER_PASSWORD on the gateway.
The runner's invalid_submission message now ends with the last attempt's schema problems (paths and rule names only, never submitted values), so agent.finished and the run viewer show why an agent was stopped. GitHub keeps the generic message.
Agent output schemas are now strict, so a misspelled field (relevant_paths for relevantPaths) is rejected by name in the error the model sees, instead of being dropped as an extra while the real field reads as missing. When an agent is stopped for invalid submissions, the message also lists the top-level field names it sent (names only, never values).
@jacobprall

Copy link
Copy Markdown
Collaborator Author

Superseded by the Postgres removal PR: the run viewer read from Postgres, and we're keeping the template database-free. Its telemetry, rejection-reason, and strict-schema fixes carried over.

@jacobprall jacobprall closed this Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant