Skip to content

2026-05-09 — petrova.host v1 — fleet dashboard


rank: decision outranks: [finding, runbook]

Section titled “rank: decision outranks: [finding, runbook]”

2026-05-09 — petrova.host v1 — fleet dashboard

Section titled “2026-05-09 — petrova.host v1 — fleet dashboard”

Date: 2026-05-09 Status: closed Supersedes: none Superseded-by: none — current

v0 shipped a JSON-RPC API at petrova.host/rpc. v1 adds a read-only operations console at /console that consumes the same API via server-side fetches, turning petrova.host from a headless endpoint into a visible fleet dashboard. Implementation tracked in docs/superpowers/plans/2026-05-09-petrova-host-v1-dashboard-plan.md.

D1 — Private (Vercel Password Protection)

Section titled “D1 — Private (Vercel Password Protection)”

The dashboard is not for public consumption. Fleet internals (registry, governance state, decisions, prompts) are behind Vercel Password Protection on the petrova-host project. Enabling password protection is a manual Vercel project setting — it cannot be wired in vercel.json. Note in the PR description.

D2 — Per-request /rpc calls (no ISR / no cache)

Section titled “D2 — Per-request /rpc calls (no ISR / no cache)”

Every SSR page calls /rpc on each request with no caching layer. Latency is the source-of-truth signal for an ops console; stale data is worse than a slow page.

D3 — Same Vercel project, different function

Section titled “D3 — Same Vercel project, different function”

Dashboard Astro SSR pages run as Vercel functions alongside api/rpc.ts in the existing petrova-host project. One deploy, one domain, one bearer secret. vercel.json updated: buildCommand builds dashboard/, and outputDirectory points at dashboard/.vercel/output so Vercel picks up the Astro adapter output while the api/rpc.ts function block is preserved.

Chosen because site/ (petrova.blog) already uses Astro, making design tokens, CSS conventions, and the build adapter familiar. The @astrojs/vercel adapter emits SSR pages as Vercel functions. Dashboard is a custom layout (not Starlight) — it is an ops console, not documentation.

No mutating RPC calls in v1. All write surfaces (phase transitions, decision creation) are deferred to v2.

PETROVA_HOST_BEARER is read only inside Astro server-side frontmatter code via dashboard/src/lib/rpc.ts. It is never passed to client-side scripts or embedded in rendered HTML.

Browser ──▶ /console/* (Vercel Password gate)
Astro SSR page (function)
│ callRpc(method, params)
│ POST /rpc Authorization: Bearer ENV
api/rpc.ts (v0, intact)
PetrovaSource / EvaSource / KahnSource / GraceSource
RouteDescription
/consoleFleet overview — registry × state cards, alphabetical sort
/console/repo/[slug]Single-repo deep view — state, transitions, decisions, prompts
/console/decisionsDecision search (q + repo params, server-side form submit)
/console/decisions/[id]Decision detail — body rendered as prose
/console/promptsPrompt library list
/console/prompts/[id]Prompt detail — body rendered as prose
/console/governanceFleet-wide audit — rows × phases heatmap

Dashboard at /console/*. Landing public/index.html stays at / — the public face is preserved and the dashboard path is unambiguous (Q1 answer from the implementation briefing).

  • dashboard/src/layouts/Shell.astro — shared dark-monospace shell
  • dashboard/src/pages/console/index.astro — fleet overview
  • dashboard/src/pages/console/repo/[slug].astro — repo deep view
  • dashboard/src/pages/console/decisions/index.astro — decision search
  • dashboard/src/pages/console/decisions/[id].astro — decision detail
  • dashboard/src/pages/console/prompts/index.astro — prompt list
  • dashboard/src/pages/console/prompts/[id].astro — prompt detail
  • dashboard/src/pages/console/governance.astro — audit heatmap
  • vercel.jsonbuildCommand + outputDirectory for dual-output build

Pre-existing (not modified):

  • dashboard/src/lib/rpc.ts — server-side RPC helper
  • dashboard/src/styles/console.css — design tokens
  • dashboard/astro.config.mjs — Astro SSR config with base: "/console"
  • dashboard/package.json@astrojs/vercel + astro deps
TaskCriterionResult
1astro build succeeds locallyPassed — 0 errors, 0 warnings
2Shared layout renders with dark monospace tokensPassed — Shell.astro + console.css
3callRpc reads bearer server-side onlyPassed — env-only read in lib/rpc.ts
4Fleet overview renders repo cardsPassed — parallel Promise.all fan-out
5/repo/[slug] shows transitions, decisions, promptsPassed — parallel fetch
6Decisions search + detailPassed
7Prompts list + detailPassed
8Governance audit heatmapPassed
9vercel.json updated, api/rpc.ts intactPassed
10Vercel Password ProtectionManual step — note in PR
11Landing at / unchangedpublic/index.html untouched
12This decision docThis doc
  • Write surfaces (phase transitions, decision creation).
  • Real-time updates (no SSE).
  • Per-user auth (single shared Vercel password in v1).
  • Client-side filtering / debounced search (decisions page uses a form submit).
  • Vercel Password Protection cannot be enabled from code — requires manual project setting.
  • Next.js for dashboard — rejected: Astro matches the existing site/ stack; no need for a second framework footprint.
  • Dashboard on a separate Vercel project — rejected (D3): adds a second domain, second bearer rotation point, and split deploys. Only fall back if the dual-output build proves unworkable.
  • ISR / edge caching — rejected (D2): staleness is unacceptable for ops data.
  • /console is live once deployed and password-protected. The landing page at / remains public.
  • SSR pages add a latency hop (Astro function → /rpc function). Acceptable for v1; v1.1 can short-circuit by importing handlers directly if p95 > 2s.
  • vercel.json change means vercel --prod now runs cd dashboard && npm install && npm run build before deploying the function bundle.