Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b63e6d3
fix(trader): fix 8 failing /status endpoint tests with mock-based app…
Fato07 May 20, 2026
6317ddb
feat(dashboard): add operator admin auth and runtime proxy route
Fato07 May 20, 2026
cb82bb2
feat(dashboard): add read-only /operator page with status card and ad…
Fato07 May 20, 2026
9673e32
feat(db): add operator_events migration for audit log
Fato07 May 20, 2026
b8641c1
feat(dashboard): add start/stop mutation controls with confirmation d…
Fato07 May 20, 2026
4c5cc52
chore(dashboard): commit untracked files from m2-schedule-routes-and-…
Fato07 May 20, 2026
4b98435
docs: add Operator Safety Control Plane section and mission docs
Fato07 May 20, 2026
dcd999a
fix(tests): replace secret-like test fixture token with non-secret st…
Fato07 May 20, 2026
bdf37f9
feat(trader): add VAL-STATUS-010/014/022/024 test coverage for /statu…
Fato07 May 20, 2026
28c911c
test(dashboard): add VAL-ADMIN-019 and VAL-ADMIN-021 test coverage fo…
Fato07 May 20, 2026
410acc5
test(dashboard): add VAL-ADMIN-014, VAL-ADMIN-018, VAL-ADMIN-020 test…
Fato07 May 20, 2026
9a72d8d
feat(dashboard): harden /operator page with VAL-UI-003/004/014-018 co…
Fato07 May 20, 2026
cd5b4ff
test(trader): fix gap_doc assertion to gap_reason in treasury dry-run…
Fato07 May 20, 2026
e093e2e
test(dashboard): add missing VAL-AUDIT-006-009,014,016-017 coverage f…
Fato07 May 21, 2026
a5651d0
docs(architecture): fix wrong file paths for admin routes and auth mo…
Fato07 May 21, 2026
b1d4fc2
fix(dashboard): fix broken lint script, add eslint devDeps, add senti…
Fato07 May 21, 2026
eee5b92
fix(tests): replace secret-like test fixture tokens with non-secret s…
Fato07 May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ PRISM_EVIDENCE_DB_CONNECTORS=1
CONNECTOR_SECRETS_KEY=BASE64_32_BYTE_CONNECTOR_KEY_HERE
# Required by /api/connectors control-plane routes and the /connectors wizard.
CONNECTOR_ADMIN_TOKEN=CHANGE_ME_CONNECTOR_ADMIN_TOKEN
# Required by /api/admin/* operator control-plane routes. Completely separate
# from CONNECTOR_ADMIN_TOKEN — connector tokens do NOT grant operator access.
OPERATOR_ADMIN_TOKEN=CHANGE_ME_OPERATOR_ADMIN_TOKEN
# Internal URL used by dashboard admin routes to proxy requests to the trader.
# Set to http://localhost:3201 for local development, or the Railway private
# network hostname in production.
TRADER_INTERNAL_URL=http://localhost:3201
# Keep private-network MCP URLs disabled in hosted deployments. Self-hosted local
# smoke tests may opt in explicitly.
# CONNECTOR_ALLOW_PRIVATE_URLS=0
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,6 @@ apps/docs/.source/

# Prism CLI local receipts
.prism/

# Runtime logs
*.log
58 changes: 48 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Latest URL-verified MCP validation on 2026-05-17 settled at <https://sepolia.bas
| `/builder-fees` | Execution attribution — Prism trade receipts with Polymarket-compatible builder codes; fee totals appear only when fill-price data is present |
| `/stats` | Receipt-linked activity stats — validations, Arc anchors, x402 calls, builder attribution, latency, calibration |
| `/calibration` | Sentinel calibration evidence — startup discrimination gate plus private corpus summary |
| `/operator` | Operator Safety Control Plane — trader status card, start/stop scheduler with confirmation dialog, audit events table (requires `OPERATOR_ADMIN_TOKEN`) |

### Infrastructure

Expand All @@ -103,7 +104,7 @@ Latest URL-verified MCP validation on 2026-05-17 settled at <https://sepolia.bas
- **Dual x402 facilitator scaffold** — public x402 payments settle on Base Sepolia today; Arc Testnet Circle-facilitator mode is implemented behind `X402_FACILITATOR_MODE` and remains off until Circle publishes a stable Arc facilitator endpoint.
- **@prism/builder-codes** — shared workspace package for HMAC-based builder code extraction from ERC-8004 agent IDs
- **Remotion pitch video** — 90s parameterized composition at `apps/pitch-video/`, served on port 3001
- **3 Neon migrations** — `001_fill_price`, `002_requester_address`, `003_treasury_events`
- **5 Neon migrations** — `001_fill_price`, `002_requester_address`, `003_treasury_events`, `004_tool_connectors`, `005_operator_events`

### External x402 + MCP Endpoint

Expand Down Expand Up @@ -187,6 +188,37 @@ uv run python -m prism_calibration.cli --help

---

## Operator Safety Control Plane

Runtime observability and safe control for Prism's autonomous trader — read status, start/stop scheduler with auth, audit trail for all mutations.

### Key Components

| Component | Description |
|-----------|-------------|
| **Trader `GET /status`** | Read-only endpoint returning 8 fields: `scheduler_running`, `interval_minutes`, `auto_pipeline_enabled`, `trade_mode`, `last_tick_timestamp`, `next_tick`, `last_error`, `service_version`. Reading status **never** starts the scheduler. |
| **Dashboard operator-admin auth** | All admin routes gated by `OPERATOR_ADMIN_TOKEN` (Bearer header). Verified via `timingSafeEqual` (separate from `CONNECTOR_ADMIN_TOKEN`). Invalid or missing token → 401 + audit row with `result=unauthorized`. |
| **Dashboard admin API routes** | `GET /api/admin/runtime`, `POST /api/admin/schedule/start`, `POST /api/admin/schedule/stop`, `GET /api/admin/audit` — proxy to the trader with auth enforcement. |
| **Operator page (`/operator`)** | Read-only status card + start/stop mutation buttons with confirmation dialog + live audit events table. Requires admin auth. |
| **`operator_events` audit log** | Append-only Postgres table (`infra/db/migrations/005_operator_events.sql`). Every mutation attempt (success, failure, unauthorized) writes a row. No UPDATE or DELETE issued by application code. |

### Key Safety Invariants

- **Reading status never starts the scheduler.** The `GET /status` endpoint is purely observational.
- **`PRISM_TRADE_MODE` is read-only (env-only).** The API cannot switch between `paper` and `live`. To change trade mode, update the environment variable and redeploy.
- **`AUTO_PIPELINE=false` is the default and cannot be changed via API.** The scheduler must be explicitly started by an authenticated operator action; start only activates the tick scheduler, not auto-pipeline.
- **Start cannot switch paper→live.** If `PRISM_TRADE_MODE=paper`, the start endpoint only starts in paper mode. No runtime escalation.
- **Stop cancels background tasks.** The stop endpoint cancels the scheduler's asyncio background task and sets `scheduler_running=false`.

### Environment Variables

| Variable | Description |
|----------|-------------|
| `OPERATOR_ADMIN_TOKEN` | Bearer token for admin API routes and `/operator` page access. Must be set in both trader and dashboard services. Verified via `timingSafeEqual` — separate from `CONNECTOR_ADMIN_TOKEN`. |
| `TRADER_INTERNAL_URL` | Internal URL where the dashboard reaches the trader service (e.g. `http://prism-trader.railway.internal:3201` for Railway private networking). |

---

## On-Chain State

Both agents are registered on Arc testnet's ERC-8004 IdentityRegistry:
Expand Down Expand Up @@ -347,11 +379,11 @@ Companion showcase film: **[Prism showcase film](https://youtu.be/ZmSStvqNgIo)**

| Service | Stack | Key Endpoints |
|---------|-------|---------------|
| **Trader** | Python, FastAPI, Mirascope | `POST /trigger`, `GET /health`, `POST /treasury/park`, `POST /treasury/unpark` |
| **Trader** | Python, FastAPI, Mirascope | `POST /trigger`, `GET /health`, `GET /status`, `POST /schedule`, `DELETE /schedule`, `POST /treasury/park`, `POST /treasury/unpark` |
| **Sentinel** | Python, FastAPI, DSPy | `POST /validate`, `GET /health` |
| **Polymarket Gateway** | Node, Hono, V2 SDK | `GET /markets`, `GET /markets/recommended`, `GET /markets/resolve`, `POST /trade`, `GET /health` |
| **MCP Server** | Python, FastMCP | Live at sentinel `/mcp` — validation, stats, manifest, issue-ledger, receipt verification, and verdict explanation tools |
| **Dashboard** | Next.js 16, React 19 | Public routes + `/api/public/stats`, `/api/public/history`, `/api/public/traces/[id]/report` |
| **Dashboard** | Next.js 16, React 19 | Public routes + `/api/public/stats`, `/api/public/history`, `/api/public/traces/[id]/report`, `/api/admin/runtime`, `/api/admin/schedule/start`, `/api/admin/schedule/stop`, `/api/admin/audit`, `/operator` |
| **CLI** | Python, Typer | `prism doctor`, `prism demo`, `prism inspect`, `prism stats`, `prism history`, `prism report`, `prism markets`, `prism market resolve`, `prism quote`, `prism validate` |
| **Pitch Video** | Remotion | `apps/pitch-video/` — parameterized 90s composition on port 3001 |

Expand Down Expand Up @@ -393,6 +425,8 @@ cp .env.example .env
# - X402_FACILITATOR_MODE (public or circle — public Base Sepolia is live; circle is scaffolded)
# - X402_ARC_RECIPIENT_ADDRESS (USDC recipient on Arc Testnet when facilitator mode is circle)
# - USYC_ARC_TESTNET_ADDRESS (optional USYC token contract address; empty = treasury dry-run)
# - OPERATOR_ADMIN_TOKEN (Bearer token for operator admin routes and /operator page)
# - TRADER_INTERNAL_URL (internal URL for dashboard → trader proxy, e.g. http://prism-trader.railway.internal:3201)

# 3. Install Python dependencies
uv sync
Expand All @@ -401,11 +435,13 @@ uv sync
pnpm install

# 5. Run database migrations
# Apply the three Neon migrations in order:
# Apply the five Neon migrations in order:
uv run python -m prism_schemas.migrations 001_fill_price
uv run python -m prism_schemas.migrations 002_requester_address
uv run python -m prism_schemas.migrations 003_treasury_events
# Or apply all at once via Neon's SQL editor / psql using the SQL files in packages/schemas-python/migrations/
uv run python -m prism_schemas.migrations 004_tool_connectors
uv run python -m prism_schemas.migrations 005_operator_events
# Or apply all at once via Neon's SQL editor / psql using the SQL files in infra/db/migrations/
```

### Running Services
Expand Down Expand Up @@ -439,14 +475,14 @@ cd apps/dashboard && pnpm test

| Suite | Tests |
|-------|-------|
| Dashboard | 475 |
| Dashboard | 650 |
| CLI | 10 |
| Polymarket Gateway | 93 |
| Sentinel | 118 |
| Trader | 156 |
| Trader | 237 |
| Calibration | 149 |
| Docs (protocol + fixtures) | 82 |
| **Total** | **1,083** |
| **Total** | **1,339** |

---

Expand Down Expand Up @@ -530,15 +566,17 @@ pnpm --dir apps/docs test

## Database Migrations

Three Neon migrations ship with the traction sprint:
Five Neon migrations ship with the traction sprint:

| Migration | Description |
|-----------|-------------|
| `001_fill_price` | Adds `fill_price` column to trades table for tracking paper/live fill prices |
| `002_requester_address` | Adds `requester_address` column to validations table for wallet-connected attribution |
| `003_treasury_events` | Creates `treasury_events` table for USYC park/unpark audit trail |
| `004_tool_connectors` | Creates `tool_connectors` table for Connector Passport MCP-first evidence connector registry |
| `005_operator_events` | Creates `operator_events` append-only audit log for scheduler start/stop/update_interval actions |

Apply them in order via the migration runner or directly through Neon's SQL editor using the files in `packages/schemas-python/migrations/`.
Apply them in order via the migration runner or directly through Neon's SQL editor using the SQL files in `infra/db/migrations/`.

---

Expand Down
Loading