Architecture¶
Geometry in → CAS engine → fan out to providers → server-side subset → zonal stats → QC → results out
CAS is a passthrough service: it stores no data and holds no database. Every request is satisfied live from the upstream provider, validated, harmonized, and returned.
Layers¶
- Connectors (
cas.connectors) — one self-contained module per provider. Each subclassesBaseConnector, implementslist_datasets()andextract(), and self-registers with the@register("slug")decorator. - Protocol mixins — WCS, STAC+COG, OPeNDAP behaviours compose into a connector via multiple inheritance, so a new provider reuses transport, parsing, and windowed-read logic.
- Registry (
cas.core.registry) —discover()imports every connector module to trigger registration;list_providers()/get_connector(slug)enumerate and resolve them at runtime. - Engine (
cas.extract) — fans a request out across the requested datasets, enforces per-provider and whole-request deadlines, computes zonal statistics (continuous: mean/median/min/max/std; categorical: majority/distribution), runs QC, and assembles the response. Results are cached in-memory. - API (
cas.api) — a FastAPI app (create_app()), with middleware for the request-ID + error envelope, optional API-key auth and rate limiting, and Prometheus metrics. - SDK (
cas.client) — a typed HTTP client returning the same models.
Quality control¶
- Range checks against each variable's declared valid range.
- Coverage thresholds — a result over a polygon with little real data is
flagged (
partial/degraded). - Cross-provider consistency — when multiple providers answer the same request (e.g. several DEMs), divergence surfaces as a warning.
Health monitoring¶
CAS ships an end-to-end health system. cas health runs a real extract() per
provider over a coverage-aware test polygon — a small area chosen inside the
provider's own declared bbox, so country-specific connectors are exercised over
data they actually serve rather than a single fixed global point. Snapshots are
compared against a committed health/baseline.json so only genuine regressions
alert; the daily CI workflow archives history and opens an issue on regression.
Adding a provider¶
- Create
src/cas/connectors/my_provider.py. - Subclass
BaseConnector(+ a protocol mixin), implementlist_datasets()andextract(). - Decorate the class with
@register("my_provider"). - Run
cas export-inventoryto refresh the catalog. - Add
tests/connectors/test_my_provider.py.
@register("my_provider")
class MyProviderConnector(WCSMixin, BaseConnector):
slug = "my_provider"
display_name = "My Provider"
base_url = "https://api.example.com"
protocol = "wcs"
async def list_datasets(self) -> list[Dataset]: ...
async def extract(self, dataset_id, geometry, time_range=None) -> AttributeResult: ...