feat(web): Observatory skeleton + read-only API (Day 15–16, M5 PR 1 of 3)#34
Merged
furkankoykiran merged 4 commits intomainfrom Apr 24, 2026
Merged
Conversation
Introduces apps/api/ — a read-only adapter over the runner's jsonl
artefacts (debate_log.jsonl, shapley_history.jsonl, runner_metrics.json).
Exposes:
GET /healthz
GET /stats
GET /runner/metrics
GET /debates/recent
GET /debates/{debate_id}
GET /shapley/leaderboard
GET /shapley/history
GET /payout/latest (null until the Day 22 graph hook)
WS /live/debates (2s poll + 10s heartbeat)
The app is a separate entrypoint: adds a `cli api` subcommand that
imports uvicorn lazily, so `cli run` (the systemd runner) stays free
of FastAPI imports. No writes, no mutation endpoints, no on-chain code.
Adds fastapi, uvicorn[standard], websockets to dependencies and httpx
to the dev group for the FastAPI TestClient.
Three new offline tests under tests/test_offline.py, taking the suite from 20 to 23: test_readers_debate_log_limit — malformed line skipped, limit respected test_readers_shapley_history_respects_k — k + keys contract test_stats_endpoint_shape — FastAPI TestClient round-trip All fixtures monkeypatch apps.api.paths.DATA_DIR onto tmp_path, so the suite stays fully offline and network-free.
First cut of apps/web, a read-only SPA over the Observatory API: / Observatory hero stats + live agent-reasoning stdout + recent table /debates debate list + filtering (link-through to detail) /debates/:id transcript + pyth + jupiter + dry-run + shapley /shapley leaderboard + hand-rolled SVG trend (no chart lib) /payout placeholder until the Day 22 graph hook lands Built with Vite + React 19 + Tailwind 3.4 + TanStack Query; terminal monospace aesthetic, single accent colour, feedback button stub. Live feed via a WebSocket hook with exponential-backoff reconnect. apps/web is a standalone pnpm package (its own pnpm-lock.yaml) so the existing `typecheck solana-agent` CI job stays untouched. Vite dev server on 5173 proxies /api → 127.0.0.1:8081 and /live → ws://…:8081 to match the FastAPI backend in the same repo.
Adds a third CI job that runs `pnpm typecheck` and `pnpm build` in apps/web on every push / PR. Uses apps/web/pnpm-lock.yaml for the Node action cache so it stays independent of the solana-agent lane. Branch protection addition (require "web typecheck + build") happens after the job has a green run on main — user action, not part of this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Day 15–16 of 33. First PR of M5 (Observatory + MCP + pitch), inserted after a strategic replan at end of Day 14 that moved the old Day 15–16 scope (fee skim + payout graph hook) to M6 (Days 21–22). Rationale: competitor SwarmHaul has a live devnet observatory + public MCP endpoint + pitch page live on the web; Quorum has been CLI + jsonl only, so judges can't see any of the technical depth unless they
git clone && uv sync. This block closes that visibility gap.One PR for the two-day block (pivot exception to the one-PR-per-day rule — backend + frontend ship nothing demo-able if split).
What landed
apps/api/— read-only FastAPI adapter over the runner's jsonl artefacts. No writes, no mutation endpoints, no on-chain code. Endpoints:GET /healthz,/stats,/runner/metricsGET /debates/recent,/debates/{debate_id}GET /shapley/leaderboard,/shapley/historyGET /payout/latest(null until the Day 22 graph hook)WS /live/debates— 2s poll + 10s heartbeatapps/orchestrator/cli.py— newcli apisubcommand that lazy-imports uvicorn, socli run(the systemd runner) stays free of FastAPI imports.apps/web/— Vite + React 19 + Tailwind 3.4 + TanStack Query SPA. Standalone pnpm package (own lockfile), so the existingtypecheck solana-agentCI lane is untouched. Four routes:/Observatory — hero stats + live agent-reasoning stdout + recent table/debates,/debates/:id/shapley— leaderboard + hand-rolled SVG trend (no chart lib)/payout— placeholder for M6ProtocolTelemetryfooter (23 tests · devnet/fork · RFB-04/05/02 · git sha).k;/statsendpoint shape round-trips throughStatsResponse.web typecheck + build, cachingapps/web/pnpm-lock.yaml.Deferred to M6 (Days 21–22)
_make_payout_nodegraph hook +payout_dry_runstate field (old Day 16)./payout/latestdeliberately returns{payout: null, message: "payout node lands Day 22"}until the graph hook lands.Verification
uv run pytest tests/test_offline.py -q→ 23 passeduvx ruff check . && uvx ruff format --check .→ cleancd packages/solana-agent && pnpm typecheck→ cleancd apps/web && pnpm typecheck && pnpm build→ clean (84 KB gzipped JS)uv run python -m apps.orchestrator.cli api --port 8081→curl /statsreturns real runner numbers (total=2, debates_count=58, shapley_rows=27 at time of smoke)cd apps/web && pnpm dev→ 5173 proxies/apiand/liveto the API cleanly; all 4 routes render without console errors{type: "ping"}within 10sNext PR
Days 17–18:
apps/mcp-server/— public MCP endpoint (TS,@modelcontextprotocol/sdk, 8 tools) so Claude Desktop and other agents can query Quorum debates + submit symbols.Scope guardrails respected
No on-chain code · No new specialists · No writes to jsonl · No deploys ·
QUORUM_LIVEandQUORUM_PAYOUT_LIVEuntouched · Ports 8000 (Divimero) and 8080 (Freqtrade) not touched.