Skip to content

Latest commit

 

History

History
197 lines (160 loc) · 12 KB

File metadata and controls

197 lines (160 loc) · 12 KB
# SWARM-GUARD UNIFIED

Multi-agent geospatial intelligence platform for real-time road safety monitoring in Kerala, India. Uses 13 specialized AI agents organized into 3 clusters (SWARM-GUARD, DRISHTI, SENTINEL), orchestrated via LangGraph with Byzantine fault-tolerant voting and Bayesian belief fusion.

## ABSOLUTE CONSTRAINTS — NEVER VIOLATE

1. **Never use random number generators for risk scores.** Every risk_score must be computed from real external data (weather readings, traffic speeds, NCRB accident stats, CV detections). If data unavailable → risk_score=0.0, confidence=0.0, vote=HOLD. Never fabricate a number.

2. **Never use `time.sleep()`.** Entire app is async. Use `asyncio.sleep()` if waiting needed. Use `asyncio.gather()` for parallel agents. Blocking the event loop is a production-killing bug.

3. **Never hardcode credentials.** All secrets from `.env` via `python-dotenv` → `backend/config.py` Pydantic BaseSettings. App must validate ALL required env vars at startup and `sys.exit(1)` listing missing ones.

4. **Never return placeholder causal attribution.** Attribution comes from Claude API (`claude-sonnet-4-20250514`). If API fails → log error, set `causal_attribution=None`, post Slack alert with raw scores marked "⚠️ Causal attribution unavailable — analysis engine returned error at {timestamp}. Manual review recommended." Never invent attribution. Never use template. Never say "high risk detected".

5. **Never skip database persistence.** Every monitoring cycle output → PostgreSQL. If DB unreachable → buffer in Redis `persistence_queue` → background coroutine drains with exponential backoff. Never drop events silently.

6. **Never exceed API rate limits.** Per-API tracking in Redis (token bucket/sliding window). If exhausted → skip agent, return confidence=0.0, vote=HOLD. Never get keys revoked.

7. **Every file must be complete and runnable.** No `pass`, `...`, `# TODO`, `raise NotImplementedError`, stubs, or truncation. No imports referencing nonexistent modules.

8. **Build order is sacred.** Each phase produces testable increment. Don't skip ahead.

## Tech Stack

- **Backend:** Python 3.12, FastAPI, SQLAlchemy (async), PostgreSQL+PostGIS, Redis, LangGraph
- **AI/ML:** YOLOv8, RT-DETR, OSNet, Anthropic Claude API (Sonnet for inner calls)
- **Frontend:** Next.js 14, Leaflet.js, Recharts, Tailwind CSS, Socket.IO
- **Infra:** Docker Compose, Alembic migrations, structlog JSON logging
- **Alerting:** Slack Bolt SDK (Socket Mode)

## Project Structure

```
swarm-guard-unified/
├── CLAUDE.md                          ← you are here
├── .env.example
├── .env                               ← never commit, never read in Claude Code
├── docker-compose.yml
├── Makefile
├── backend/
│   ├── config.py                      ← Pydantic BaseSettings, @lru_cache singleton
│   ├── requirements.txt               ← pinned versions
│   ├── Dockerfile
│   ├── agents/
│   │   ├── base.py                    ← BaseAgent ABC + AgentOutput schema
│   │   ├── weather_friction.py        ← Open-Meteo + OpenWeatherMap fallback
│   │   ├── historical_pattern.py      ← NCRB accident data
│   │   ├── traffic_anomaly.py         ← HERE Traffic Flow API v7
│   │   ├── visual_risk.py             ← YOLOv8 object detection
│   │   ├── situation_awareness.py     ← IMD warnings (DRISHTI)
│   │   ├── resource_inventory.py      ← KSDMA resources (DRISHTI)
│   │   ├── population_vulnerability.py ← Census 2011 (DRISHTI)
│   │   ├── logistics_optimizer.py     ← OR-Tools VRP (DRISHTI)
│   │   ├── counterfactual.py          ← Claude projection (DRISHTI)
│   │   ├── edge_perception.py         ← RT-DETR (SENTINEL)
│   │   ├── cross_camera.py            ← OSNet Re-ID (SENTINEL)
│   │   ├── threat_escalation.py       ← Bayesian Beta-Binomial (SENTINEL)
│   │   └── evidence_packaging.py      ← Section 65B compliance (SENTINEL)
│   ├── api/
│   │   ├── main.py                    ← FastAPI app, lifespan, middleware
│   │   └── routes/
│   │       ├── health.py              ← GET /health, GET /health/ratelimits
│   │       ├── segments.py            ← GET /segments, /segments/{id}, /segments/{id}/events
│   │       └── websocket.py           ← WebSocket /ws/riskmap
│   ├── models/
│   │   ├── base.py                    ← async SQLAlchemy engine + session
│   │   ├── segment.py                 ← RoadSegment ORM (PostGIS geometry)
│   │   ├── event.py                   ← RiskEvent ORM (JSONB agent_scores)
│   │   ├── historical.py              ← HistoricalAccident (NCRB data)
│   │   ├── disaster_resource.py       ← DisasterResource (KSDMA)
│   │   └── census.py                  ← CensusData (2011)
│   ├── orchestrator/
│   │   ├── state.py                   ← GeospatialBeliefState TypedDict
│   │   ├── voting.py                  ← Byzantine fault-tolerant weighted voting
│   │   ├── belief_fusion.py           ← Bayesian fusion with correlation correction
│   │   ├── coordinator.py             ← 3-stage: vote → fuse → Claude attribution
│   │   ├── graph.py                   ← LangGraph StateGraph wiring
│   │   └── monitor.py                 ← Continuous monitoring loop + rate limits
│   └── services/
│       ├── database.py                ← persist_event + Redis queue fallback
│       └── slack_service.py           ← Bolt SDK, Block Kit alerts, slash commands
├── frontend/
│   ├── package.json
│   ├── Dockerfile
│   └── src/app/
│       ├── page.tsx                   ← Leaflet map + side panel
│       ├── events/page.tsx            ← Events table
│       └── health/page.tsx            ← System health
├── scripts/
│   ├── seed_segments.py               ← 6 Kerala road segments
│   ├── parse_ncrb.py                  ← NCRB accident data
│   ├── seed_disaster_resources.py     ← KSDMA inventory
│   └── seed_census.py                 ← Census 2011 data
├── tests/
│   ├── test_agents/                   ← per-agent tests
│   ├── test_orchestrator/             ← voting, fusion, coordinator, graph
│   ├── test_api/                      ← endpoint tests
│   ├── test_services/                 ← Slack, DB tests
│   └── test_integration/             ← full pipeline E2E
└── alembic/                           ← async migrations
```

## Agent Architecture

### AgentOutput Schema (every agent returns this):
```python
agent_name: str
risk_score: float   # 0.0-1.0, from REAL data, NEVER random
confidence: float   # 0.0-1.0, trust level
vote: "ESCALATE" | "HOLD" | "DISMISS"  # >0.70 ESCALATE, <0.30 DISMISS, else HOLD
metadata: dict      # raw API data, intermediate calculations
timestamp: datetime
data_sources_used: list[str]
```

### Graceful failure (any agent, any error):
```python
risk_score=0.0, confidence=0.0, vote="HOLD",
metadata={"error": str(error), "fallback": True}
```

### 3 Clusters:

**SWARM-GUARD (road safety):** weather_friction, historical_pattern, traffic_anomaly, visual_risk → run in parallel

**DRISHTI (disaster response):** situation_awareness, resource_inventory, population_vulnerability, logistics_optimizer, counterfactual → run in parallel

**SENTINEL (surveillance):** edge_perception + cross_camera (parallel) → threat_escalation (sequential) → evidence_packaging (sequential)

## Orchestration Pipeline (per segment, per cycle)

1. **Agents run** → collect AgentOutput list
2. **Byzantine Voting** → weighted sum: ESCALATE +1×conf, HOLD 0, DISMISS -1×conf. Sum >+0.50 ESCALATE, <-0.50 DISMISS, else HOLD. Exclude confidence=0 agents. >50% failed → degraded mode.
3. **Bayesian Belief Fusion** → fuse scores accounting for correlation (Visual+Traffic ρ=0.6). Independent: weighted average. Correlated: down-weighted. Combined via precision weighting.
4. **Coordinator** → if DISMISS stop. If HOLD+low belief stop. Else → Claude API causal attribution → persist → Slack alert if ESCALATE or belief >0.72 → Redis publish for WebSocket.

## External APIs (all verified free-tier)

| API | Agent | Key | Limit | Endpoint |
|-----|-------|-----|-------|----------|
| Open-Meteo | weather_friction | No | 10K/day | api.open-meteo.com/v1/forecast |
| OpenWeatherMap | weather_friction (fallback) | Yes | 60/min, 1K/day | api.openweathermap.org/data/2.5/weather |
| HERE Traffic v7 | traffic_anomaly | Yes | 1K/day | data.traffic.hereapi.com/v7/flow |
| Anthropic Claude | coordinator + counterfactual | Yes | 60 RPM | claude-sonnet-4-20250514 |
| IMD Warnings | situation_awareness | No | ~100/day | mausam.imd.gov.in |

## 6 Monitored Kerala Road Segments

1. NH-66 Edapally Junction, Ernakulam — 10.0261,76.3125 → 10.0350,76.3089 — asphalt, 60km/h, 4 lanes
2. NH-544 Thrissur-Palakkad — 10.5276,76.2144 → 10.5400,76.1980 — asphalt, 80km/h, 4 lanes
3. NH-66 Kasaragod Bypass — 12.5010,74.9893 → 12.5150,74.9820 — asphalt, 70km/h, 2 lanes
4. MC Road Kottayam-Changanassery — 9.5916,76.5222 → 9.5750,76.5350 — concrete, 50km/h, 2 lanes
5. SH-1 Wayanad Ghat Road — 11.6854,76.1320 → 11.6700,76.1200 — wbm, 30km/h, 2 lanes (9 hairpins)
6. NH-66 Kozhikode Beach Road — 11.2588,75.7804 → 11.2500,75.7750 — asphalt, 40km/h, 4 lanes

## Key Formulas

**Friction (IRC SP:73-2015):** base × (1-rain_reduction) × (1-temp_reduction) × humidity × wind
**Historical risk:** min(1.0, district_rate / (2 × 14.2)) × time_multiplier × day_multiplier
**Traffic risk:** 0.6 × (1 - speed/freeflow) + 0.4 × (jamFactor/10)
**Belief fusion:** (μ_indep × prec_indep + μ_corr × prec_corr) / (prec_indep + prec_corr)

## Rate Limit Schedule

MONITORING_INTERVAL_SECONDS=300 (5min). 6 segments per cycle.
- Open-Meteo: every cycle = 1,728/day ✓ (under 10K)
- HERE: once per segment per hour = 144/day ✓ (under 1K)
- OpenWeatherMap: fallback only
- Anthropic: only on ESCALATE/HOLD-above-threshold

## Code Standards

- **Async everywhere:** asyncio, httpx.AsyncClient, create_async_engine, async_sessionmaker
- **Retry:** tenacity @retry max_attempts=3, wait_exponential with jitter on all HTTP calls
- **Logging:** structlog JSON with request_id context
- **Types:** Full type hints on every function parameter and return
- **Testing:** pytest + pytest-asyncio, real API calls in integration tests, mocked failures in unit tests
- **Linting:** ruff check + ruff format

## Build Order (sacred)

Phase 0-2: Scaffold + DB + FastAPI → Phase 3: BaseAgent → Phase 4: Weather → Phase 5: Historical → Phase 6: Traffic → Phase 7: Visual → Phase 8-9: Voting + Fusion → Phase 10: Coordinator → Phase 11: Graph + Monitor → Phase 12: Slack → Phase 13: DRISHTI (5 agents) → Phase 14: SENTINEL (4 agents) → Phase 15: Rate Limits → Phase 16: Frontend → Phase 17: Integration Tests

## Environment Variables (.env)

```
ANTHROPIC_API_KEY=
OPENWEATHERMAP_API_KEY=
HERE_API_KEY=
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
SLACK_CHANNEL_ID=
DATABASE_URL=postgresql+asyncpg://swarmguard:swarmguard@localhost:5432/swarmguard
REDIS_URL=redis://localhost:6379/0
MONITORING_INTERVAL_SECONDS=300
LOG_LEVEL=INFO
```