Commit Graph

7 Commits

Author SHA1 Message Date
Jordan Ritter 1b0aa557ba fix(showcase/shell-dashboard): keep client ops fetch same-origin via /api/ops
The staging D6 dashboard rendered no data because the client did a direct
cross-origin fetch to the harness URL — CORS-blocked and the wrong path
(`/probes` instead of `/api/probes`). Root cause: getRuntimeConfig() sourced
the client RuntimeConfig.opsBaseUrl from the server proxy target OPS_BASE_URL
(the harness URL), which the root layout serialized into
window.__SHOWCASE_CONFIG__, so resolveBaseUrl() used it as the fetch base
instead of falling through to the same-origin /api/ops proxy.

Decouple the two: the client direct override is now an explicit, opt-in,
client-intended env var (NEXT_PUBLIC_OPS_DIRECT_BASE_URL) that defaults to ""
in every environment, so the client lands on /api/ops. The Route Handler's
server-only OPS_BASE_URL read and its sentinel behavior are unchanged.

- showcase/shell-dashboard/src/lib/runtime-config.ts: opsBaseUrl now read from
  NEXT_PUBLIC_OPS_DIRECT_BASE_URL (default ""), not OPS_BASE_URL; no sentinel.
- showcase/shell-dashboard/src/lib/ops-api.ts: update resolveBaseUrl comments
  to describe the client override vs server proxy target distinction.
- showcase/shell-dashboard/src/app/layout.tsx: note opsBaseUrl is the client
  override, never the harness URL.
- tests: encode the contract (client falls through to /api/ops when no direct
  override; server proxy target does not leak into the client config), incl. an
  end-to-end regression in the env-switch spike test.
2026-06-01 08:14:03 -07:00
Jordan Ritter b19c27f045 fix(showcase/shell-dashboard): resolve OPS_BASE_URL at runtime via /api/ops route handler
The /api/ops/* proxy was a next.config.ts rewrite, which Next.js evaluates at
`next build` and freezes into the prebuilt Docker image. The shared CI build
bakes a placeholder OPS_BASE_URL (http://ops.invalid) to satisfy a
throw-if-unset guard, so every deploy of the single :latest image proxied to a
dead host regardless of its runtime env — /api/ops/* returned 500
(ENOTFOUND ops.invalid), the Feature Matrix health overlay got no probe data,
and every cell downgraded to amber (zero green) despite green backend data.
The same freeze also baked the production harness URL into the shared image,
so even a correct rebuild would point staging at the prod harness.

Replace the build-time rewrite with a Route Handler at
src/app/api/ops/[...path]/route.ts that reads process.env.OPS_BASE_URL at
REQUEST time (force-dynamic, never statically cached) and proxies
/api/ops/<path> -> ${OPS_BASE_URL}/api/<path>, forwarding method, query
string, headers, and body. A missing OPS_BASE_URL now returns a clear 503
instead of a build throw. The build no longer depends on OPS_BASE_URL.

This fixes both traps with one image: each environment resolves its own
runtime OPS_BASE_URL from the same artifact, no rebuild. Requires the
dashboard image to rebuild + redeploy. Harness path is now /api/probes.
2026-06-01 07:46:27 -07:00
Jordan Ritter 8714ab569b chore(showcase): apply oxfmt formatting across showcase scripts and shells
oxfmt --write normalized formatting on showcase scripts, the four shells, and the
new oxlint rule; required for the repo-root oxfmt --check CI gate.
2026-05-29 11:45:16 -07:00
Jordan Ritter f2ba6b2564 test(showcase): add no-rebuild env-switch integration test (spike replay)
Replay the Option B runtime-config spike as a vitest integration test
that guards the no-rebuild env switching property going forward:

  - `next build` once with no per-env URL env vars (only a sentinel
    OPS_BASE_URL so next.config.ts's rewrites() can validate; Next
    evaluates rewrites at build, not only at start, so a placeholder
    here is unavoidable — the assertions don't depend on it).
  - `next start` twice, each on a fresh port and a DIFFERENT
    POCKETBASE_URL / SHELL_URL / OPS_BASE_URL set.
  - Fetch `/` on each boot and extract the inlined
    `window.__SHOWCASE_CONFIG__={...}` JSON from the served HTML.
  - Assert env-A URLs on the first boot and env-B URLs on the second
    boot of the SAME built artifact. If anyone re-introduces a
    build-time URL bake, the second boot's HTML still shows env-A
    values and this test fails.

Test lives at `showcase/shell-dashboard/tests/runtime-env-switch.spike.test.ts`
and is picked up via a new vitest include for `tests/**/*.spike.test.ts`
(the default include is `src/**/*.test.{ts,tsx}` and the integration-
weight spike doesn't fit there). The `.spike.test.ts` suffix keeps
the include narrow so the visual snapshot suite under
`tests/visual/` stays out.

Total wall time locally: ~12s (build ~2s warm with prebuild data
generation already run; two boots ~10s combined). Heavy enough to
gate behind a `tests:integration` script in CI rather than running
on every push.
2026-05-29 11:45:09 -07:00
Jordan Ritter 3f88ad2c90 fix(showcase-dashboard): align e2e key lookup with probe dimension
The e2e-demos probe writes per-demo rows keyed as e2e:<slug>/<featureId>
but resolveCell looked up e2e_smoke:<slug>/<featureId>. The mismatch
caused every per-demo depth chip to show gray (no data), leaving cells
stuck at D2. Fix: read the e2e dimension the probe actually writes.
2026-04-24 22:20:14 -07:00
Jordan Ritter 9bce821779 feat(shell-dashboard): Phase 3 dashboard honesty pass
Phase 3.0: Pre-flight verified — 34 e2e_smoke rows in PB (producer
gap from PR #4200 resolved).

Phase 3.1: Rename dashboard e2e subscription to e2e_smoke to match
ops producer key. Update formatLabel/formatTooltip dim unions.

Phase 3.2: Add per-integration L1-L4 LevelStrip with Up/Wired/Chats/
Tools badges. New subscriptions for agent, chat, tools, e2e_smoke.
Widen aggregateConnection to variadic. Tools n/a gate uses
integration.demos.some(d => d.id === "tool-rendering").

Phase 3.3: Retire HealthDot from per-feature cells (L1 Up badge in
strip replaces it). Drop smokeRow from per-cell rollup (Decision #7).
Rollup now uses [healthRow, e2eRow] only. First-ever green rollups
enabled (smokeRow was always null in production).

Phase 3.4: Remove QA column — drop LiveBadge QA, CellState.qa,
subscription, legend entry. No producer ever existed.

Phase 3.5: Docs four-glyph mapping: ok->checkmark, missing->middle
dot, notfound->cross, error->exclamation. Each DocState has a
distinct glyph and tone.

Phase 3.6: Legend rewrite — drop QA/Hosted, add L1-L4 strip docs,
expand docs row for four glyphs, rewrite ? footnote.

Phase 3.7: Add PackagesSection below starters grid. Extends
registry.json with packages array from shared/packages.json. CI
drift test ensures package set matches integration set.
2026-04-23 09:14:05 -07:00
Jordan Ritter 7f3fab47b2 feat(showcase/shell-dashboard): live PocketBase status wiring + tests
Replace the static status.json feed with a live PocketBase subscription
(useLiveStatus / useLastTransition hooks + live-status lib + pb client),
add vitest + playwright visual test setup, wire feature-grid + cell
pieces + badges to the live data model. Adds Dockerfile + .dockerignore
for Railway deployment of the dashboard.
2026-04-22 11:00:46 -07:00