VesperSpatial (Delphi-1.0)

Live

Actuarial spatial catastrophe underwriting engine and $25M PML accumulation grids. Built for California surplus lines carriers and treaty reinsurers. Sub-42ms quote API, live ERA5 wind and dryness anomalies, and California CDI compliance under Producer of Record #4501603.

Problem

Legacy catastrophe models run in 15-minute to 4-hour batches, blind to bind-time cluster risk. Cluster wildfires breach treaty limits, while California CDI mandates forward-looking cat modeling.

Business & Systems Impact

  • Sub-42ms actuarial rating API endpoint latency at bind time
  • Enforces strict $25M PML spatial accumulation ceilings within 5-mile radius rings
  • Integrates ECMWF ERA5 real-time atmospheric reanalysis for dynamic hazard loadings
  • Calibrated for 45%–55% target loss ratios across high-risk California brush corridors
  • Engineered under California Producer of Record (#4501603) regulatory frameworks

Key Metrics

Sub-42ms Latency

$25M PML Grids

ERA5 Wind/Dryness

CA Producer #4501603

Solution Architecture

FastAPI + PostGIS spatial microservice stack enforcing $25M PML accumulation rings within 5-mile buffers, live ERA5 atmospheric reanalysis, and a Next.js 16 WebGL carrier control plane with sub-42ms latency.

VesperSpatial Delphi-1.0 Actuarial Underwriting Stack

React Flow mini map

Key Implementation Details

PostGIS $25M PML Accumulation Ring Enforcement
@router.post("/v1/quote/accumulate", response_model=PMLAccumulationResponse)
async def evaluate_pml_accumulation(quote: PolicyQuoteRequest, db: AsyncSession = Depends(get_db)):
    """
    Enforces $25M Probable Maximum Loss (PML) accumulation ceiling
    within a 5-mile geospatial radius ring using PostGIS ST_DWithin.
    """
    query = select(
        func.sum(PolicyExposure.insured_value).label("current_pml"),
        func.count(PolicyExposure.id).label("active_policies")
    ).where(
        func.ST_DWithin(
            PolicyExposure.geom,
            func.ST_SetSRID(func.ST_MakePoint(quote.lon, quote.lat), 4326)::geography,
            8046.72  # 5 miles in meters
        ),
        PolicyExposure.status == PolicyStatus.BOUND
    )
    result = await db.execute(query)
    current_pml = result.scalar() or Decimal("0.00")
    
    if current_pml + quote.requested_tiv > Decimal("25000000.00"):
        raise PMLBreachException(
            f"Exceeds $25M PML cluster ceiling. Current cluster exposure: ${current_pml:,.2f}"
        )
    return PMLAccumulationResponse(authorized=True, cluster_pml=current_pml + quote.requested_tiv)
ECMWF ERA5 Real-Time Hazard Loading Engine
async def compute_era5_brush_loading(lat: float, lon: float, date: datetime) -> float:
    """
    Queries ECMWF ERA5 reanalysis tensor slice for 10m wind gust and 2m relative humidity.
    Computes dynamic wildfire burn spread velocity loading factor.
    """
    era5_point = await era5_client.sample_point(lat=lat, lon=lon, timestamp=date)
    wind_speed_ms = era5_point.wind_speed_10m
    rh_percent = era5_point.relative_humidity_2m
    
    # Non-linear spread rate index based on fuel moisture deficit
    fuel_deficit = max(0.0, (1.0 - (rh_percent / 100.0)))
    wind_loading = math.exp(0.069 * wind_speed_ms)
    hazard_multiplier = 1.0 + (fuel_deficit * wind_loading * 0.45)
    
    return min(hazard_multiplier, 3.50)  # Capped at 3.5x base rate loading

Tech Stack

FastAPIPythonPostGISPostgreSQLDuckDB-SpatialERA5 ReanalysisNext.js 16WebGLDockerCloudflare

Links