Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 0 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -588,13 +588,6 @@ KG__TOP_K=4
# codice e' su main. Vedi knowledge-graph#7 (blocco) e #6 (provider openai).
#API_KG_BASE_URL=http://host.docker.internal:8000

# =============================================================================
# Clerk auth — DEPRECATO / RIMOSSO (non ammesso per la PA).
# =============================================================================
# Sostituito dall'auth su database (blocco AUTH__ più sopra + src/limen/auth/,
# issue #49). Il codice di validazione JWT Clerk resta finché non si conclude
# la migrazione, ma è disattivato di default e non usato dal frontend.
CLERK__ENABLED=false

# =============================================================================
# limen-ops MCP server (agent tools over Limen itself)
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ src/limen/
│ ├── main.py # FastAPI app factory + lifespan
│ ├── dependencies.py # AppDependencies + typed Depends() providers
│ ├── schemas.py # Pydantic request/response DTOs
│ ├── endpoints/ # health/ready, aoi, monitor, risk, alerts, tiles
│ ├── endpoints/ # health/ready, aoi, risk, alerts, tiles
│ └── jobs/ # APScheduler: hourly_monitoring, weekly_idrogeo_sync,
│ # cache_cleanup, registration
├── notifications/ # NotificationChannel Protocol + AlertPayload + Telegram/MQTT/Email + dispatcher
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ persistenza.
| **Backtest** | replay di una finestra storica con pioggia antecedente **CERRA** (5.5 km) + truth set e-ITALICA → hit rate / FAR / lead time vs target §2.5 | one-shot | `limen backtest` + `reports/backtest_*.md` |
| **Workflow MAF (V1)** | AreaResolver → StaticFactors → MeteoFetch → SeismicCheck → FireCheck → \[SensorFetch?\] → RiskScoring → EscalationGate → RiskAnalyst → Briefing → PersistResult → AlertDispatch | one-shot CLI | `agents/` + `limen monitor-once` |
| **Provider LLM** | precedenza `LLM__PROVIDER` > Anthropic > OpenAI > Foundry > **llama.cpp**; il resolver salta i provider cloud senza SDK e cade su llama.cpp (solo httpx). Ollama resta selezionabile con `LLM__PROVIDER=ollama`. Briefing in italiano; RiskAnalyst restituisce JSON tipizzato. | risolto all'avvio | `agents/llm_factory/resolve_llm_factory` |
| **API HTTP** | `/health` + `/ready`, `POST /api/monitor/{aoi}`, `GET /api/aoi/{id}/risk/latest`, `GET /api/cell/{id}/breakdown`, `GET /api/aoi`, `GET /api/alerts`, `/api/tiles/...`, OpenAPI su `/docs` e `/redoc` | FastAPI / uvicorn | `api/` + `limen serve` |
| **API HTTP** | `/health` + `/ready`, `GET /api/aoi/{id}/risk/latest`, `GET /api/cell/{id}/breakdown`, `GET /api/aoi`, `GET /api/alerts`, `/api/tiles/...`, OpenAPI su `/docs` e `/redoc` | FastAPI / uvicorn | `api/` + `limen serve` |
| **Job periodici** | workflow MAF orario (con shadow ML), **sweep previsionale** ogni 6 h, **nowcast radar DPC** ogni 15 min, **hotspot NASA FIRMS** ogni 45 min, report nazionale giornaliero, sync ISPRA settimanale, **drift monitor ML** (PSI/KS training-vs-live sulle feature canoniche che lo shadow persiste), cache cleanup + retention di `model_runs` (default 30 gg) | APScheduler in-process | `api/jobs/` |
| **Radar DPC (nowcast)** | SRI nazionale 1 km / 5 min (piattaforma radar DPC, CC-BY-SA): pioggia ≥ `NOWCAST__MIN_INTENSITY_MMH` su una regione ⇒ il workflow di quella AOI parte subito invece di aspettare il tick orario (cooldown 45 min; alert dal percorso operativo normale) | poll ogni `NOWCAST__INTERVAL_MINUTES` | `integrations/dpc/` + `api/jobs/nowcast_monitoring.py` |
| **Hotspot NASA FIRMS** | detection attive VIIRS 375 m (S-NPP / NOAA-20 / NOAA-21) e MODIS 1 km con latenza NRT ~3 h: `FIRMS__MIN_HOTSPOTS` hotspot dentro una AOI ⇒ workflow immediato (cooldown `FIRMS__COOLDOWN_MINUTES`), e `months_since_fire` — quindi il fattore F post-incendio — si attiva in ore invece di attendere il perimetro EFFIS. Fail-closed: senza `FIRMS__MAP_KEY` il feed è inerte e il job non viene registrato | poll ogni `FIRMS__INTERVAL_MINUTES` (1 transazione per sorgente sul bbox nazionale) | `integrations/firms/` + `api/jobs/firms_monitoring.py` + `limen firms-sync` |
Expand Down
51 changes: 2 additions & 49 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ precedenza.
> temporale, da affiancare — mai sostituire — alle fonti e alle procedure
> ufficiali. Vedi anche [`docs/warning-logic.md`](./warning-logic.md).

Gli esempi seguenti usano solo endpoint **read-only** (l'unico che scrive è
`POST /api/monitor/{aoi}`, mostrato a parte). Ogni esempio riassume la **forma
Gli esempi seguenti usano solo endpoint **read-only**.Ogni esempio riassume la **forma
attesa della risposta**.

## Salute e prontezza
Expand Down Expand Up @@ -61,51 +60,6 @@ Restituisce ogni riga della tabella `aoi`:

## Esegui un ciclo di monitoraggio

```
curl -s -X POST http://localhost:8080/api/monitor/it-puglia \
-H 'content-type: application/json' \
-d '{"cell_limit": 25}' | jq
```

Corpo (opzionale):

```json
{
"cell_limit": 25,
"valuation_time": "2026-06-01T12:00:00+00:00"
}
```

Risposta:

```json
{
"aoi_id": "it-puglia",
"assessment_id": 4567,
"assessment": {
"aoi_id": "it-puglia",
"model_version": "limen-deterministic-v1",
"valuation_time": "2026-06-01T12:00:03.412678+00:00",
"n_cells": 25,
"cells_high_or_above": 2,
"cells_by_level": {"None": 21, "Low": 2, "High": 1, "VeryHigh": 1},
"top_cells": [
{"cell_id": "it-puglia|12|7", "score": 0.81, "level": "VeryHigh", ...}
],
"analysis": {"driver": "meteo_trigger", "anomalies": [...], ...},
"briefing_it": "Le condizioni osservate ..."
},
"cells_scored": 25,
"high_or_above": 2,
"dispatched_alerts": [...]
}
```

Un AOI mancante restituisce `404`. Il workflow stesso non solleva mai
eccezioni sui fallimenti delle sorgenti esterne — degrada.

## Ultima valutazione per-AOI

```
curl -s http://localhost:8080/api/aoi/it-puglia/risk/latest | jq
```
Expand Down Expand Up @@ -208,7 +162,6 @@ I codici rilevanti:

| Codice | Quando |
|---|---|
| `404` | `POST /api/monitor/{aoi_id}` con un AOI sconosciuto |
| `404` | `GET /api/aoi/{id}/risk/latest` senza alcuna valutazione persistita |
| `503` | `/ready` mentre il lifespan è in fase di bootstrap |
| `503` | `/api/tiles/...` quando `API__PG_TILESERV_URL` non è configurato |
| `503` | `/api/tiles/...` quando `API__PG_TILESERV_URL` non è configurato |
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ dependencies = [
"opentelemetry-exporter-otlp-proto-http>=1.27",
"aiomqtt>=2.3",
"aiosmtplib>=3.0",
"pyjwt[crypto]>=2.9",
]

[project.scripts]
Expand Down
77 changes: 0 additions & 77 deletions src/limen/api/auth.py

This file was deleted.

2 changes: 0 additions & 2 deletions src/limen/api/endpoints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
auth,
comuni,
health,
monitor,
risk,
tiles,
)
Expand All @@ -26,7 +25,6 @@ def all_routers() -> Iterable[APIRouter]:
return (
health.router,
aoi.router,
monitor.router,
risk.router,
alerts.router,
tiles.router,
Expand Down
67 changes: 0 additions & 67 deletions src/limen/api/endpoints/monitor.py

This file was deleted.

24 changes: 0 additions & 24 deletions src/limen/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,6 @@ class AoiListResponse(BaseModel):
items: list[AoiSummary]


class MonitorRequest(BaseModel):
model_config = ConfigDict(extra="forbid")

cell_limit: int | None = Field(
default=None,
ge=1,
description="Optional cap on the number of cells scored (smoke runs).",
)
valuation_time: datetime | None = None


class MonitorResponse(BaseModel):
"""Wrap-up of one workflow run."""

model_config = ConfigDict(extra="forbid")

aoi_id: str
assessment_id: int | None = None
assessment: AggregateAssessment | None = None
cells_scored: int = 0
high_or_above: int = 0
dispatched_alerts: list[str] = Field(default_factory=list)


class LatestAssessmentResponse(BaseModel):
"""Latest persisted assessment summary for an AOI."""

Expand Down
22 changes: 0 additions & 22 deletions src/limen/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,27 +594,6 @@ class KgSettings(BaseSettings):
top_k: int = Field(default=4, ge=1, le=20)


class ClerkSettings(BaseSettings):
"""Clerk JWT validation for protected FastAPI endpoints.

Off by default so the public, read-only map endpoints stay open and dev
/test need no Clerk config. When ``enabled``, operator endpoints (e.g.
``POST /api/monitor``) require a valid Clerk session JWT verified against
the instance JWKS (public RSA keys) — the secret key is never needed.
"""

model_config = SettingsConfigDict(extra="ignore")

enabled: bool = False
# Clerk instance JWKS endpoint (public keys):
# https://<frontend-api-domain>/.well-known/jwks.json
jwks_url: str | None = None
# Expected `iss` claim (the Clerk Frontend API origin). None ⇒ unchecked.
issuer: str | None = None
# Accepted `azp` (authorized party) origins; empty ⇒ unchecked.
authorized_parties: list[str] = Field(default_factory=list)


class AuthSettings(BaseSettings):
"""Database-backed auth (replaces Clerk — PA-compliant, self-hosted).

Expand Down Expand Up @@ -855,7 +834,6 @@ class Settings(BaseSettings):
kg: KgSettings = Field(default_factory=KgSettings)
geodata: GeodataSettings = Field(default_factory=GeodataSettings)
geoserver_source: GeoServerSourceSettings = Field(default_factory=GeoServerSourceSettings)
clerk: ClerkSettings = Field(default_factory=ClerkSettings)
auth: AuthSettings = Field(default_factory=AuthSettings)
spid: SpidSettings = Field(default_factory=SpidSettings)

Expand Down
Loading