# Project export: CabVector

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: CabVector: turning transit disruptions into safe, proactive taxi staging across New York City.
- Devpost: https://devpost.com/software/frontline-7rhyzg
- GitHub: https://github.com/rayhanf14/CabVector
- Video: https://www.youtube.com/embed/bmxSlPEHnmo?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Aayush-c23 (19 commits), rayhanf14 (8 commits), Anup Bhandarkar (1 commits)

## Devpost submission (written by the team)

### Inspiration

Have you ever been stranded when an NYC subway line suddenly goes down? It’s pure chaos. Hundreds of frustrated people pour out onto the street looking for a ride, while nearby roads instantly gridlock. We wanted to solve this dual problem: how can we proactively guide taxis toward stranded passengers without turning the surrounding streets into a parking lot? That question sparked the idea for CabVector. How We Built It We built CabVector from the ground up as a full-stack web application: The Brain (Backend): We used FastAPI to handle the state management, scoring logic, safety workflows, and live API endpoints. The Interface (Frontend): Next.js powers our multi-page interactive dashboard. The Map: Leaflet and CARTO tiles bring the data to life, visualizing the disruptions, map legends, and staging zones. The Integrations: We built hooks for MTA, NYC DOT, OpenAI, and Groq APIs. Knowing that live demos can be risky, we engineered dependable fixture data so the app runs flawlessly even without API keys. The entire system is governed by a strict, deterministic workflow: $$ \text{Fleet proposal} \rightarrow \text{Traffic validation} \rightarrow \text{Approved dispatch} $$ A taxi's state doesn't change until it passes through every single checkpoint. A dispatch is only approved if it makes sense for both the driver's wallet and the city's traffic grid: $$ (L\text{-Score} > 70) \land (\text{Congestion Index} \leq 0.7) $$ Challenges We Ran Into If you've ever worked with live public city data, you know the struggle. Transit and traffic feeds are notoriously flaky—authentication methods change, responses lag, and connections drop out of nowhere. Instead of letting the app break, we engineered resilient fallback mechanisms and live health indicators. If a provider goes down, the dashboard stays functional and is completely transparent about what data is missing. Another massive headache was keeping everything perfectly in sync. Ensuring the map, fleet state, alerts, and backend decisions were all telling the same story required us to nail down clear shared contracts and rely heavily on server-sent events. What We Learned This project was a masterclass in building operational AI. We learned that these systems absolutely need reliable fallbacks, transparent rules, and a hard wall between an AI's "suggestion" and a system's "action." On the technical side, we leveled up our skills in real-time state synchronization, map visualizations, and collaborative full-stack architecture. We also had a great time using Codex (powered by GPT-5.6) as an engineering copilot. It was incredibly helpful for untangling integration bugs and organizing our implementation phases, proving its worth as a collaborator rather than a runtime dispatch engine.

## README (from the GitHub repository)

# CabVector

CabVector is a simulated New York City/MTA pre-emptive taxi-staging system. It detects sustained transit disruption, estimates displaced passenger demand, produces a driver-facing Lucrativeness Score (L-Score), recommends nearby staging zones, validates traffic safety, and models approved movement of a 20-taxi fleet.

This repository is an MVP simulator, not a passenger-booking app, live taxi-dispatch system, fare engine, or traffic-signal controller.

## How it works

1. A transit delay above 600 seconds must persist for three minutes before it becomes a disruption.
2. Passenger spill and historical station footfall determine the integer L-Score (1–100).
3. An L-Score above 70 permits Fleet to propose available taxis for a staging zone.
4. Traffic approves only congestion at or below 0.7.
5. Only an approval can call the state-update function that dispatches taxis.

## Project layout

| Area | Responsibility |
| --- | --- |
| `backend/main.py` | FastAPI application, fixture-backed in-memory state, and API routes |
| `backend/core/` | Shared models and deterministic score calculation |
| `backend/agents/` | Approval-gated Fleet → Traffic → Action workflow |
| `backend/data/` | Recorded hourly footfall fixture for the demo |
| `backend/tests/` | API, scoring, and agent workflow tests |
| `frontend/` | Next.js dashboard with live API integration and an interactive Leaflet/CARTO Dark Matter map |

## Delivery status

The table below is the current repository-wide plan. A phase is only fully complete when every listed workstream is complete.

| Phase | Developer / workstream | Status | Delivered or pending work |
| --- | --- | --- | --- |
| Phase 0 — alignment and contracts | All developers | Complete | NYC/MTA simulation boundary, safety rules, shared Pydantic models, shared TypeScript contracts (`frontend/types/contracts.ts`), static fixtures (`frontend/lib/fixtures.ts`), and frozen API examples. |
| Phase 1 — platform and API | Developer A | Complete | FastAPI application, configuration boundary, seeded state, `GET /api/state`, `POST /api/trigger_agent`, and SSE endpoint. |
| Phase 1 — data and scoring | Developer B | Complete | Footfall fixture, recorded scoring scenarios, deterministic passenger-spill calculation, and 1–100 L-Score engine. |
| Phase 1 — agent workflow | Developer C | Complete | Strict workflow schemas, deterministic Fleet → Traffic → Action graph, congestion veto, L-Score gate, and approval-only state update boundary. |
| Phase 1 — dashboard shell | Developer D | Complete | Next.js dashboard layout, map/control split, status indicators, KPI cards, alert feed, and terminal shell using static contract fixtures. |
| Phase 2 — API integration | Developer A | Complete | Two-second state polling and structured SSE delivery for the dashboard. |
| Phase 2 — transit and spatial data | Developer B | Complete | GTFS-RT fixture flattening, three-minute structural-delay validation, and 3–5 staging zones within 300 metres. |
| Phase 2 — dispatch behavior | Developer C | Complete | Nearest-taxi selection plus rejected-zone retry to a farther staging area; taxis remain unchanged until approval. |
| Phase 2 — visual simulation | Developer D | Complete | Interactive NYC map, disruption and staging-zone overlays, clickable taxi markers, alerts, KPI updates, and structured event terminal wired to the live API. |
| Phase 3 — live-data adapters and hardening | Developers A–D | Implementation complete; partially live-validated | MTA subway GTFS-RT and Bus Time SIRI reached `online` in a local run. NYC DOT traffic may be `degraded` when its public host is unreachable; the documented fixture fallback remains the correct behavior. |
| Phase 4 — quality, demo, UI redesign, and release | All developers | Complete | Complete UI redesign matching deep obsidian theme (`#090D16`), official logo badge integration, in-map search bar (`⌘ K`), 3-column status bottom deck (`BottomDeck.tsx`), 37/37 backend unit tests passing, Next.js 14 production build verified across all 10 routes. |

Phase 4 is complete and verified. The repository is fully tested, built, and ready for production shipping.

## API

| Endpoint | Purpose |
| --- | --- |
| `GET /api/state` | Returns disruptions, staging zones, taxis, and recent decision events. |
| `POST /api/trigger_agent` | Triggers the fixture-backed dispatch decision. |
| `GET /api/events` | Streams structured decision events over Server-Sent Events. |
| `GET /api/health` | Returns safe provider status, mode, timestamps, and record counts; never returns credentials or raw upstream payloads. |

The frozen request and response examples are in [HANDOFF.md](HANDOFF.md).

## Live provider inventory

The complete Phase 3 provider/data list, polling intervals, credentials, fallbacks, and safety rules is in [docs/API_DATA_INVENTORY.md](docs/API_DATA_INVENTORY.md). Keep `LIVE_FEEDS_ENABLED=false` until the configured provider endpoints and keys have been tested against the fixture-backed fallback.

## Agent safety workflow

The deterministic traffic adapter returns `0.5` by default. It can be configured above `0.7` to verify the veto path. Fleet and Traffic never modify taxi records directly. The workflow uses one approval-only integration point:

```python
def apply_approved_dispatch(update: DispatchConfirmation) -> None:
    """Persist dispatched taxis after Traffic approval."""
```

The `DispatchConfirmation` payload contains `station_id`, `assigned_zone_id`, `dispatched_taxis`, and `final_congestion_index`, matching the public `DISPATCH_CONFIRMED` event.

## Fixture data

`backend/data/turnstile_data.csv` is a small committed demo fixture, not a live MTA export. The score engine uses an exact station-and-hour lookup and aggregates duplicate observations before scoring.

| Column | Meaning |
| --- | --- |
| `station_id` | Stable station or stop identifier |
| `station_name` | Human-readable station name |
| `hour` | Local hour from 0 through 23 |
| `footfall` | Historical passenger count for that station and hour |

Missing footfall is deliberately surfaced as unscored; CabVector does not substitute nearby stations or network averages.

## Run and test the backend

Install the dependencies listed in `backend/requirements.txt`, then start the API from the repository root:

```powershell
uvicorn backend.main:app --reload
```

Run the completed API, deterministic workflow, and scoring tests across all workstreams:

```powershell
python -m unittest discover backend/tests -v
```

## Live traffic, map, and AI configuration

Copy `.env.example` to `.env`. To use the public NYC DOT traffic feed, set `LIVE_FEEDS_ENABLED=true`; its default URL needs no API key. The feed supplies observed sensor speeds, and CabVector derives its congestion index against `NYC_DOT_REFERENCE_SPEED_MPH` (default `30`). The default live-provider timeout and Bus Time/traffic polling intervals are 60 seconds to tolerate slow public feeds.

**MTA Realtime Feeds (Keyless):** MTA subway feeds no longer require an API key. To query live subway delay updates keylessly, leave `MTA_GTFS_API_KEY` blank in your `.env` file. The server will automatically fetch data without authorization headers.

For an optional structured operator-summary report, configure Groq or OpenAI in your `.env`:

```dotenv
LLM_PROVIDER=groq
GROQ_API_KEY=your_key
GROQ_MODEL=llama-3.1-8b-instant
```

Use `LLM_PROVIDER=openai` with `OPENAI_API_KEY` and `OPENAI_MODEL` for OpenAI instead. When configured, the backend spawns a non-blocking background task to request a structured JSON summary from the LLM and prints it cleanly to the console terminal (avoiding encoding issues on Windows). `LLM_PROVIDER=deterministic` is the default and remains the only mode that drives the dispatch workflow; LLM output cannot approve or move taxis.

## Custom Disruptions, Surge-Lock Fare, and Animated Taxis

1. **Custom Disruption Injection:** The Control Panel features a drop-down menu of major NYC stations and an 

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 77 recognized source files, 325 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (88 of 88)

```
.env.example
.gitignore
backend/agents/__init__.py
backend/agents/fleet_agent.py
backend/agents/orchestrator.py
backend/agents/schemas.py
backend/agents/traffic_agent.py
backend/config.py
backend/core/__init__.py
backend/core/gtfs_parser.py
backend/core/live_data.py
backend/core/llm_provider.py
backend/core/score_engine.py
backend/core/staging.py
backend/core/state.py
backend/data/turnstile_data.csv
backend/main.py
backend/requirements.txt
backend/tests/.gitkeep
backend/tests/fixtures/gtfs_rt_fixture.json
backend/tests/fixtures/transit_delay_fixtures.json
backend/tests/test_agent_workflow.py
backend/tests/test_api.py
backend/tests/test_frontend_contracts.py
backend/tests/test_gtfs_parser.py
backend/tests/test_live_data.py
backend/tests/test_llm_provider.py
backend/tests/test_score_engine.py
backend/tests/test_staging.py
CABVECTOR_IMPLEMENTATION.md
docs/API_DATA_INVENTORY.md
frontend/app/about/page.tsx
frontend/app/analytics/page.tsx
frontend/app/dispatches/page.tsx
frontend/app/fleet/page.tsx
frontend/app/globals.css
frontend/app/incidents/page.tsx
frontend/app/layout.tsx
frontend/app/page.tsx
frontend/app/providers/page.tsx
frontend/app/settings/page.tsx
frontend/app/simulation/page.tsx
frontend/app/zones/page.tsx
frontend/components/AgentTerminal.tsx
frontend/components/AlertFeed.tsx
frontend/components/BottomDeck.tsx
frontend/components/ControlPanel.tsx
frontend/components/design-system/Button.css
frontend/components/design-system/Button.tsx
frontend/components/design-system/SpotlightCard.css
frontend/components/design-system/SpotlightCard.tsx
frontend/components/design-system/TextType.css
frontend/components/design-system/TextType.tsx
frontend/components/design-system/Typography.css
frontend/components/design-system/Typography.tsx
frontend/components/FleetMatrix.tsx
frontend/components/Header.tsx
frontend/components/LiveMap.tsx
frontend/components/MapWorkspace.tsx
frontend/components/ProductPage.tsx
frontend/lib/fixtures.ts
frontend/next-env.d.ts
frontend/next.config.mjs
frontend/package.json
frontend/postcss.config.js
frontend/styles/variables.css
frontend/tailwind.config.ts
frontend/tests/.gitkeep
frontend/tests/verify_contracts.ts
frontend/tsconfig.json
frontend/types/contracts.ts
frontend/types/providers.ts
HANDOFF.md
react-design-system/ai-instructions.md
react-design-system/src/components/Button/Button.css
react-design-system/src/components/Button/Button.jsx
react-design-system/src/components/DecryptedText/DecryptedText.css
react-design-system/src/components/DecryptedText/DecryptedText.jsx
react-design-system/src/components/InteractiveShowcase.css
react-design-system/src/components/InteractiveShowcase.jsx
react-design-system/src/components/SplitText/SplitText.css
react-design-system/src/components/SplitText/SplitText.jsx
react-design-system/src/components/SpotlightCard/SpotlightCard.css
react-design-system/src/components/SpotlightCard/SpotlightCard.jsx
react-design-system/src/components/Typography/Typography.css
react-design-system/src/components/Typography/Typography.jsx
react-design-system/src/styles/variables.css
README.md
```

### Dependencies

- backend/requirements.txt: fastapi@>=0.100.0, gtfs-realtime-bindings@>=1.0.0, httpx@>=0.24.0, pandas@>=2.0.0, pydantic@>=2.0.0, pydantic-settings@>=2.0.0, python-dotenv@>=1.0.0, sse-starlette@>=1.6.0, uvicorn@>=0.23.0
- frontend/package.json: @types/leaflet@^1.9.21, @types/node@^20.14.10, @types/react@^18.3.3, @types/react-dom@^18.3.0, autoprefixer@^10.4.19, gsap@^3.15.0, leaflet@^1.9.4, next@^14.2.5, postcss@^8.4.39, react@^18.3.1, react-dom@^18.3.1, react-leaflet@^4.2.1, tailwindcss@^3.4.4, typescript@^5.5.3

### Recent commits (newest first)

- docs: finalize Phase 4 completion and ready-to-ship documentation
- feat: complete UI redesign, dark obsidian theme, official logo, and bottom deck integration
- feat: add animated taxis, surge-lock fare, custom disruptions, keyless MTA feeds, and structured LLM reports
- Merge pull request #10 from rayhanf14/Rayhan-Branch
- New UI
- New UI
- Merge pull request #9 from rayhanf14/Rayhan-Branch
- Phase 3 Complete, API Calls changes, Impl plan changed
- phase 3 complete all tasks
- Merge pull request #8 from rayhanf14/phase-2-completion
- Complete Phase 2: Core dispatch loop and visual simulation
- feat(dashboard): implement Phase 1 Next.js dashboard shell and update documentation
- Merge pull request #7 from rayhanf14/phase-0/dashboard-contracts
- docs: synchronize Phase 0 and Developer D status across README and implementation guide
- feat(dashboard): complete Developer D Phase 0 TypeScript contracts and fixtures
- Merge pull request #6 from rayhanf14/phase-1/platform-api
- docs: update README test command to discover all 14 repository unit tests
- Merge pull request #5 from rayhanf14/Anup-Branch
- dev c phase 0 and phase 1 done and readme updated
- Merge pull request #4 from rayhanf14/phase-1/platform-api

## Key source files (fetched from GitHub, selected and truncated for size)

### CABVECTOR_IMPLEMENTATION.md

```markdown
# CabVector Implementation Guide

## MVP boundary

Build the CabVector New York / MTA taxi-dispatch simulator. It detects sustained transit disruption, estimates displaced passenger demand, creates nearby taxi-staging zones, obtains traffic approval, and shows the decision and simulated taxi movement in a dashboard.

The earlier GBFS/e-bike direction is out of scope. Real driver dispatch, accounts, persistent storage, real pricing, and traffic-signal control are post-MVP work.

## Intended architecture

`MTA GTFS-RT + MTA Bus Time` and the public `NYC DOT Traffic Speed` feed a FastAPI backend. The backend calculates disruption state, passenger spill, Lucrativeness Score, staging zones, and mocked taxi state. A deterministic workflow coordinates Fleet -> Traffic -> Action; OpenAI or Groq may be selected later for display-only operator summaries. A Next.js dashboard reads backend state and renders an interactive NYC digital twin with Leaflet and CARTO Dark Matter tiles.

## Repository map

| Location | Planned responsibility |
| --- | --- |
| `backend/main.py` | FastAPI application entry point and API routes |
| `backend/config.py` | Environment-variable configuration |
| `backend/requirements.txt` | Python dependencies |
| `backend/data/turnstile_data.csv` | Historical MTA footfall input |
| `backend/core/gtfs_parser.py` | GTFS-RT and transit-event parsing |
| `backend/core/score_engine.py` | Passenger spill and Lucrativeness Score logic |
| `backend/core/staging.py` | H3/GeoPandas staging-zone generation |
| `backend/core/state.py` | In-memory disruption, taxi, and event state |
| `backend/agents/orchestrator.py` | Fleet -> Traffic -> Action workflow |
| `backend/agents/fleet_agent.py` | Nearby taxi selection and route proposal |
| `backend/agents/traffic_agent.py` | Congestion/capacity validation |
| `backend/tests/` | Backend fixtures and automated tests |
| `frontend/app/` | Next.js layout, dashboard page, and global styling |
| `frontend/components/` | Map, controls, alerts, and agent-terminal UI |
| `frontend/tests/` | Frontend and end-to-end tests |

## Required data contracts

Implement these as validated backend models before connecting live feeds:

- `DisruptionEvent`: station ID, station name, latitude/longitude, passenger spill, Lucrativeness Score.
- `MockTaxi`: taxi ID, latitude/longitude, status (`available`, `proposed`, or `dispatched`), staging-zone ID.
- `StagingZone`: zone ID, station ID, latitude/longitude, capacity, congestion index, walking radius.
- `AgentDecisionEvent`: timestamp, actor, event type, operator-safe message, and JSON payload.

Do not put model chain-of-thought in the terminal. Render only structured decision events.

## Build sequence

### 1. Establish local environments

Create a Python virtual environment and a Next.js/Node environment. Add dependency manifests and `.env.example` entries for MTA, public NYC DOT traffic, and OpenAI/Groq. Use Leaflet with CARTO Dark Matter tiles for the map; keep all real keys
[truncated — 19811 more characters]
```

### docs/API_DATA_INVENTORY.md

```markdown
# CabVector API and Data Inventory

This inventory is the source of truth for live data and map services. Operational data-provider calls occur from the FastAPI backend; the browser loads public CARTO Dark Matter base-map tiles directly.

| Source | Purpose | Authentication and polling | CabVector data used | Fallback |
| --- | --- | --- | --- | --- |
| MTA subway GTFS-Realtime | Rail trip-update disruption detection | `MTA_SUBWAY_TRIP_UPDATES_URL`, optional `MTA_GTFS_API_KEY`; 15 seconds | `vehicle_id`, `route_id`, `stop_id`, `delay_seconds` from protobuf Trip Updates | Recorded GTFS fixture and seeded state |
| MTA Bus Time SIRI VehicleMonitoring | Bus telemetry and schedule deviation | `MTA_BUS_TIME_API_KEY`; 60 seconds | `MonitoredVehicleJourney`, planned/expected arrival times, vehicle, route, stop | Recorded SIRI-compatible test payload; unmatched records remain unscored |
| NYC DOT Traffic Speed Detectors | Congestion validation around staging zones | Public `NYC_DOT_TRAFFIC_SPEED_URL`; 60 seconds | Nearest sensor-link observed speed; normalized to a 0-1 CabVector congestion index using the configured project reference speed | Zone fixture congestion (`0.5`) |
| MTA turnstile CSV | Historical footfall for the L-Score | Committed local CSV | `station_id`, `station_name`, `hour`, `footfall` | Same committed fixture |
| CARTO Dark Matter tiles via Leaflet | Interactive NYC dashboard map | No API key; browser tile requests; visible OpenStreetMap/CARTO attribution | Dark base map plus disruption, staging-zone, and taxi coordinate overlays; visible marker legend | Map loading shell; dispatch data remains available |
| OpenAI or Groq | Optional display-only operator summary | Select one with `LLM_PROVIDER`; server-side key and model only | Safe summary text only; no tool access, approval, or state mutation | Deterministic Fleet -> Traffic -> Action workflow |

## Provider safety rules

1. `LIVE_FEEDS_ENABLED` defaults to `false`.
2. Missing configuration disables a provider; a request failure marks it degraded. Neither case replaces fixture state with invented data.
3. Only an exact station/stop mapping can affect an active `DisruptionEvent`. Unknown mappings remain unscored.
4. The NYC DOT congestion index is CabVector's derived ratio: `1 - observed_speed_mph / NYC_DOT_REFERENCE_SPEED_MPH`, clamped to `0..1`. NYC DOT does not provide this project-specific score or a free-flow-speed field.
5. `LLM_PROVIDER` accepts `deterministic`, `openai`, or `groq`. The optional client is outside the dispatch-approval path; Fleet, Traffic, and the state-update boundary remain deterministic.
6. `GET /api/health` exposes non-secret provider health to the dashboard. It reports `starting` while an enabled provider awaits its first response, and never returns keys, URLs containing credentials, or raw upstream payloads.
7. A `degraded` NYC DOT provider means the dispatch workflow continues with the last known or fixture congestion value; it must not be represented a
[truncated — 678 more characters]
```

### backend/requirements.txt

```
fastapi>=0.100.0
uvicorn>=0.23.0
pydantic>=2.0.0
pydantic-settings>=2.0.0
python-dotenv>=1.0.0
sse-starlette>=1.6.0
httpx>=0.24.0
pandas>=2.0.0
gtfs-realtime-bindings>=1.0.0

```

### frontend/package.json

```
{
  "name": "cabvector-dashboard",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@types/leaflet": "^1.9.21",
    "gsap": "^3.15.0",
    "leaflet": "^1.9.4",
    "next": "^14.2.5",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-leaflet": "^4.2.1"
  },
  "devDependencies": {
    "@types/node": "^20.14.10",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "autoprefixer": "^10.4.19",
    "postcss": "^8.4.39",
    "tailwindcss": "^3.4.4",
    "typescript": "^5.5.3"
  }
}

```

### backend/main.py

```python
"""
CabVector FastAPI Application Boundary (`backend/main.py`)

This module implements:
1. FastAPI initialization, CORS policy (`CORS_ORIGINS`), and lifespan management.
2. In-memory `SystemState` container seeded with Developer B's Phase 1 disruption fixture (`Grand Central-42 St`, L-Score 85).
3. Contract-valid endpoints (`GET /api/state`, `POST /api/trigger_agent`, and `GET /api/events` Server-Sent Events).
"""

import asyncio
import math
import time
from contextlib import asynccontextmanager
from typing import List, AsyncGenerator, Set, Dict, Any
from fastapi import FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from sse_starlette.sse import EventSourceResponse, ServerSentEvent

from backend.config import settings
from backend.core.state import (
    DisruptionEvent,
    MockTaxi,
    StagingZone,
    AgentDecisionEvent,
    SystemState,
    TaxiStatus,
    get_current_timestamp,
)
from backend.core.gtfs_parser import DelayTracker
from backend.core.staging import generate_staging_zones
from backend.core.live_data import (
    MtaBusTimeSiriClient,
    MtaGtfsRealtimeClient,
    ProviderHealthRegistry,
    ProviderHealthSnapshot,
    NycDotTrafficClient,
)
from backend.agents.orchestrator import AgentOrchestrator, WorkflowResult
from backend.agents.schemas import DispatchConfirmation
from backend.agents.traffic_agent import CurrentZoneTrafficAdapter, TrafficAgent
from backend.core.llm_provider import resolve_llm_runtime_config, generate_operator_summary
import json


# --- Request Validation Models ---
class TriggerAgentRequest(BaseModel):
    """Payload sent by frontend or agent workflow to request fleet assignment for a disruption."""
    disruption_station_id: str = Field(..., description="Target disrupted station ID")
    requested_taxis: int = Field(..., gt=0, le=20, description="Number of taxis to dispatch")
    max_walking_radius: int = Field(300, ge=0, le=300, description="Maximum walking distance in meters")

class CustomDisruptionRequest(BaseModel):
    """Payload to manually inject a custom disruption for testing."""
    station_id: str = Field(..., description="Target disrupted station ID")
    station_name: str = Field(..., description="Human-readable station name")
    latitude: float = Field(..., description="Station center latitude")
    longitude: float = Field(..., description="Station center longitude")
    passenger_spill: int = Field(..., ge=0, description="Estimated displaced passenger demand")
    l_score: int = Field(..., ge=1, le=100, description="Lucrativeness Score")
    delay_seconds: int = Field(..., ge=0, description="Sustained delay duration")



# --- In-Memory State Initialization ---
def initialize_system_state() -> SystemState:
    """Initialize the in-memory SystemState with Developer B's baseline fixture and a 20-taxi mock fleet."""
    disruptions = [
        DisruptionEvent(
            station_id="631",
            station_name="Grand Central-42 St",
            latitude=40.751776,
            longitude=-73.976848,
            passenger_spill=450,
            l_score=85,
            delay_seconds=720,
            timestamp="2026-07-16T15:00:00Z",
        )
    ]

    staging_zones = [
        StagingZone(
            zone_id="ZONE_6AV_W14_1",
            station_id="631",
            latitude=40.7519,
            longitude=-73.9769,
            capacity=5,
            congestion_index=0.5,
            walking_radius=150,
        )
    ]

    # Initialize a stable, scattered taxi fleet around the active Grand Central delay.
    taxis: List[MockTaxi] = []
    disruption_center = (40.751776, -73.976848)

    def seeded_unit(seed: int) -> float:
        value = math.sin(seed * 12.9898 + 78.233) * 43758.5453
        return value - math.floor(value)

    for i in range(1, 21):
        t_id = f"TAXI_{i:02d}"
        angle = seeded_unit(i) * math.pi * 2
        radius = 0.0012 + seeded_unit(i + 100) * 0.006
        latitude = disruption_center[0] + math.cos(angle) * radius
        longitude = disruption_center[1] + math.sin(angle) * radius * 1.28
        if i == 1:
            # First taxi matches contract example (proposed to ZONE_6AV_W14_1)
            taxis.append(
                MockTaxi(
                    taxi_id=t_id,
                    latitude=latitude,
                    longitude=longitude,
                    status=TaxiStatus.PROPOSED,
                    staging_zone_id="ZONE_6AV_W14_1",
                )
            )
        else:
            taxis.append(
                MockTaxi(
                    taxi_id=t_id,
                    latitude=latitude,
                    longitude=longitude,
                    status=TaxiStatus.AVAILABLE,
                    staging_zone_id=None,
                )
            )

    recent_events = [
        AgentDecisionEvent(
            timestamp="2026-07-16T15:00:05Z",
            actor="TrafficAgent",
            event_type="ROUTE_APPROVAL",
            operator_safe_message="Approved routing 3 taxis to staging zone ZONE_6AV_W14_1 (congestion index 0.5 <= 0.7 limit).",
            payload={
                "zone_id": "ZONE_6AV_W14_1",
                "approved_taxis": ["TAXI_01", "TAXI_02", "TAXI_03"],
                "congestion_index": 0.5,
            },
        )
    ]

    return SystemState(
        disruptions=disruptions,
        staging_zones=staging_zones,
        taxis=taxis,
        recent_events=recent_events,
    )


# Singleton in-memory state container
app_state = initialize_system_state()
provider_health = ProviderHealthRegistry(live_enabled=settings.live_feeds_enabled)
gtfs_delay_tracker = DelayTracker()
bus_delay_tracker = DelayTracker()


# --- Asynchronous Live SSE Broadcaster Setup ---
# Registry of active client event queues
sse_queues: Set[asyncio.Queue] = set()


async def broadcast_event(event_type: str, data: str) -> None:
    """Broadcast an event asynchronously to all connected client queues.
[truncated — 13938 more characters]
```

### frontend/app/layout.tsx

```typescript
import type { Metadata } from "next";
import "leaflet/dist/leaflet.css";
import "./globals.css";

export const metadata: Metadata = {
  title: "CabVector | NYC/MTA Command Center",
  description: "Pre-Emptive Taxi-Staging Command Center for MTA NYC Transit Disruptions",
  icons: {
    icon: "/logo.png",
  },
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" className="dark">
      <body>{children}</body>
    </html>
  );
}

```

### frontend/app/page.tsx

```typescript
"use client";

import React, { useState, useEffect } from "react";
import { Header } from "@/components/Header";
import { MapWorkspace } from "@/components/MapWorkspace";
import { ControlPanel } from "@/components/ControlPanel";
import { AlertFeed, AlertItem } from "@/components/AlertFeed";
import { AgentTerminal } from "@/components/AgentTerminal";
import { FleetMatrix } from "@/components/FleetMatrix";
import { INITIAL_SYSTEM_STATE } from "@/lib/fixtures";
import { SystemState, AgentDecisionEvent } from "@/types/contracts";
import {
  FIXTURE_PROVIDER_HEALTH,
  ProviderHealthSnapshot,
} from "@/types/providers";

const API_BASE_URL =
  process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000";

import { BottomDeck } from "@/components/BottomDeck";

export default function DashboardPage() {
  const [systemState, setSystemState] = useState<SystemState>(INITIAL_SYSTEM_STATE);
  const [isRunning, setIsRunning] = useState(false);
  const [alerts, setAlerts] = useState<AlertItem[]>([]);
  const [events, setEvents] = useState<AgentDecisionEvent[]>([]);
  const [providerHealth, setProviderHealth] = useState<ProviderHealthSnapshot>(
    FIXTURE_PROVIDER_HEALTH
  );

  // Poll system state every 2 seconds
  useEffect(() => {
    const fetchState = async () => {
      try {
        const response = await fetch(`${API_BASE_URL}/api/state`);
        if (response.ok) {
          const data: SystemState = await response.json();
          setSystemState(data);
        }
      } catch (err) {
        console.error("Failed to fetch system state", err);
      }
    };
    
    fetchState();
    const interval = setInterval(fetchState, 2000);
    return () => clearInterval(interval);
  }, []);

  // Health is a separate, non-secret endpoint; SystemState remains contract-stable.
  useEffect(() => {
    const fetchProviderHealth = async () => {
      try {
        const response = await fetch(`${API_BASE_URL}/api/health`);
        if (response.ok) {
          setProviderHealth(await response.json());
        }
      } catch (err) {
        console.error("Failed to fetch provider health", err);
      }
    };

    fetchProviderHealth();
    const interval = setInterval(fetchProviderHealth, 15000);
    return () => clearInterval(interval);
  }, []);

  // Connect to SSE for live events
  useEffect(() => {
    const eventSource = new EventSource(`${API_BASE_URL}/api/events`);

    eventSource.addEventListener("decision_event", (e) => {
      try {
        const eventData: AgentDecisionEvent = JSON.parse(e.data);
        
        setEvents((prev) => {
          const updated = [...prev, eventData];
          return updated.length > 50 ? updated.slice(updated.length - 50) : updated;
        });

        // Derive alerts from specific decision events
        if (eventData.event_type === "CONGESTION_REJECTION") {
          setAlerts((prev) => [
            {
              id: `alert-${Date.now()}-${Math.random()}`,
              title: "CONGESTION VETO",
              timestamp: new Date().toLocaleTimeString("en-GB", { hour12: false }),
              description: eventData.operator_safe_message,
              type: "veto",
            },
            ...prev,
          ]);
        } else if (eventData.event_type === "DISPATCH_CONFIRMED") {
          setAlerts((prev) => [
            {
              id: `alert-${Date.now()}-${Math.random()}`,
              title: "DISPATCH CONFIRMED",
              timestamp: new Date().toLocaleTimeString("en-GB", { hour12: false }),
              description: eventData.operator_safe_message,
              type: "stable",
            },
            ...prev,
          ]);
        } else if (eventData.event_type === "DISPATCH_SKIPPED") {
          setAlerts((prev) => [
             {
              id: `alert-${Date.now()}-${Math.random()}`,
              title: "DISPATCH SKIPPED",
              timestamp: new Date().toLocaleTimeString("en-GB", { hour12: false }),
              description: eventData.operator_safe_message,
              type: "warning",
            },
            ...prev,
          ]);
        }
      } catch (err) {
        console.error("Error parsing decision_event", err);
      }
    });

    return () => {
      eventSource.close();
    };
  }, []);

  const handleTriggerSimulation = async () => {
    const disruption = systemState.disruptions[0];
    if (!disruption) return;

    setIsRunning(true);
    try {
      await fetch(`${API_BASE_URL}/api/trigger_agent`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          disruption_station_id: disruption.station_id,
          requested_taxis: 3,
        }),
      });
    } catch (err) {
      console.error("Failed to trigger simulation", err);
    } finally {
      setIsRunning(false);
    }
  };

  const handleSelectTaxi = (taxiId: string) => {
    console.log(`Selected taxi: ${taxiId}`);
  };

  return (
    <div className="flex flex-col h-screen w-screen overflow-hidden bg-[#090d16] text-slate-100">
      <Header
        stationId={systemState.disruptions[0]?.station_id || "631"}
        trafficLimit={0.7}
        providerHealth={providerHealth}
      />
      <main className="flex-1 pt-[60px] flex flex-col min-h-0 overflow-hidden">
        <div className="flex-1 flex min-h-0 overflow-hidden relative">
          <MapWorkspace
            systemState={systemState}
            onSelectTaxi={handleSelectTaxi}
          />
          <aside className="dashboard-side-panel w-[320px] xl:w-[360px] h-full overflow-y-auto shrink-0 border-l border-[#1e293b]">
            <ControlPanel
              totalFleet={systemState.taxis?.length || 20}
              availableTaxis={
                systemState.taxis?.filter((t) => t.status === "available").length || 10
              }
              dispatchedTaxis={
                systemState.taxis?.filter(
                  (t) => t.status === "dispatched" || t.status === "proposed"
                ).length |
[truncated — 334 more characters]
```

### frontend/app/fleet/page.tsx

```typescript
import { ProductPage } from "@/components/ProductPage";
export default function FleetPage() { return <ProductPage page="fleet" />; }

```

### frontend/app/zones/page.tsx

```typescript
import { ProductPage } from "@/components/ProductPage";
export default function ZonesPage() { return <ProductPage page="zones" />; }

```

### frontend/app/settings/page.tsx

```typescript
import { ProductPage } from "@/components/ProductPage";
export default function SettingsPage() { return <ProductPage page="settings" />; }

```

[68 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]