Skip to content
Merged
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
63 changes: 51 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
`intent → task semantics → catalog federation → live item evidence → asset plan → manifest`

[![CI](https://github.com/GeoGeekLab/stac-scout/actions/workflows/ci.yml/badge.svg)](https://github.com/GeoGeekLab/stac-scout/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/Python-3.12%20%7C%203.13-3776AB?style=flat-square&logo=python&logoColor=white)](.github/workflows/ci.yml)
[![Python](https://img.shields.io/badge/Python-3.12%20%7C%203.13%20%7C%203.14-3776AB?style=flat-square&logo=python&logoColor=white)](.github/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-2ea44f?style=flat-square)](LICENSE)
[![STAC](https://img.shields.io/badge/STAC-evidence--first-111111?style=flat-square)](https://stacspec.org/)

Expand Down Expand Up @@ -129,17 +129,50 @@ confidence ≠ proof
## Install

```bash
python -m pip install -e ".[dev]"
python -m pip install stac-scout
```

Python 3.12 or newer is required.
Python 3.12 or newer is required. Python 3.12, 3.13, and 3.14 are tested in CI.

For Planetary Computer access recipes:

```bash
python -m pip install -e ".[planetary-computer]"
python -m pip install "stac-scout[planetary-computer]"
```

## 60-second first success

This first check is deterministic and does not call a remote catalog:

```bash
cat > request.json <<'JSON'
{
"task": "assess wildfire impact",
"place": "Lahaina, Maui",
"datetime": {
"start": "2023-08-09T00:00:00Z",
"end": "2023-08-20T23:59:59Z"
}
}
JSON

stac-scout advise request.json --task wildfire_impact
```

The important part of the output is the decision contract, not prose:

```json
{
"data_type": "optical",
"required_measurements": ["nir", "swir22"],
"follow_up_requirements": ["comparison_windows"]
}
```

Scout derives the optical/NIR/SWIR2 requirement but refuses to invent the missing comparison
window. For a live Item-to-manifest walkthrough, see
[`examples/wildfire-impact/`](examples/wildfire-impact/).

## Geo Task Intelligence

![Geo Task Intelligence workflow](docs/assets/geo-task-intelligence.svg)
Expand Down Expand Up @@ -501,8 +534,11 @@ stac-scout/
│ ├── cases/
│ ├── federation_cases/
│ ├── task_cases/
│ ├── regression_matrix.json
│ ├── runner.py
│ └── live.py
├── examples/
│ └── wildfire-impact/
├── docs/
│ ├── ARCHITECTURE.md
│ └── TASK_RULES.md
Expand All @@ -519,14 +555,14 @@ The deterministic evaluation corpus checks contracts that affect dataset decisio
python evals/runner.py
```

It covers:
It covers request invariants, modality mismatches, cloud PASS/FAIL/UNKNOWN, required versus
preferred measurements, DOI identity strength, multiple extents, antimeridian/polar AOIs,
empty and >100 Item behavior, provider timeout/429/partial failure, categorical resampling,
missing `file:size`, volume budgets, task/user conflicts, malformed provider metadata,
cross-provider identity, task derivation, temporal strategy, and follow-up requirements.

- request invariants;
- cross-provider identity;
- task-derived measurements;
- task modality;
- temporal strategy;
- follow-up requirements.
`evals/regression_matrix.json` binds the hardening acceptance scenarios to concrete pytest node
IDs, so removing a required regression causes the eval runner to fail.

Remote providers are intentionally kept out of ordinary CI.

Expand All @@ -548,7 +584,10 @@ remote catalog state

## Development

Contributor installs are editable; normal users should use the PyPI command above.

```bash
python -m pip install -e ".[dev]"
ruff check .
ruff format --check .
mypy
Expand All @@ -557,7 +596,7 @@ python evals/runner.py
python -m build
```

CI runs on Python 3.12 and 3.13.
CI runs on Python 3.12, 3.13, and 3.14. Python 3.15 prereleases are exercised as a non-blocking compatibility signal before the final 3.15 release.

Coverage must stay at or above 90%.

Expand Down
98 changes: 98 additions & 0 deletions examples/wildfire-impact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Wildfire impact: live evidence to replay

This example exercises the complete STAC Scout decision path against a real STAC API. Remote
catalog contents can change, so exact Item counts are observations rather than golden test values.
The deterministic contracts behind the workflow are covered separately by CI and `evals/`.

The AOI is a small polygon around Lahaina, Maui, and the Item window begins after the August 2023
fire. A scientifically complete before/after impact study still requires an explicit comparison
window; STAC Scout intentionally does not invent it.

## 1. Confirm task requirements

```bash
stac-scout advise examples/wildfire-impact/request.json --task wildfire_impact
```

Expected semantics:

```text
data_type: optical
required measurements: nir + swir22
temporal strategy: before_after
follow-up: comparison_windows
```

The checked-in request already carries the required modality and measurements so the remaining
live steps use the same explicit hard constraints.

## 2. Federate candidate discovery

```bash
stac-scout federate examples/wildfire-impact/request.json \
--max-workers 4 --overall-timeout 30
```

Inspect `candidates[]`, `duplicate_groups[]`, and typed `failures[]`. A provider failure does
not erase candidates from other providers.

## 3. Verify actual Items

For a stable concrete path, use Element 84 Earth Search and Sentinel-2 L2A:

```bash
stac-scout verify examples/wildfire-impact/request.json \
--provider earth-search \
--collection sentinel-2-l2a \
--max-items 20
```

The result records observed Item IDs, timestamps, asset keys, AOI coverage, and warnings. If the
provider returns exactly the cap, the observation is `limit_reached` rather than falsely called
complete.

## 4. Produce the asset plan, volume evidence, manifest, and recipe

```bash
stac-scout plan examples/wildfire-impact/request.json \
--provider earth-search \
--collection sentinel-2-l2a \
--max-items 20 \
--manifest scout.manifest.json \
--recipe load.py
```

Inspect:

- `access_plan.asset_choices[]` for measurement-to-asset evidence;
- each resampling decision and its evidence;
- `estimated_bytes` when `file:size` metadata is available, otherwise explicit UNKNOWN;
- output grid `utm` at 20 m;
- search completeness and selected Item IDs in `scout.manifest.json`.

The recipe is generated from the manifest; the manifest is the provenance record.

## 5. Replay the observation

```bash
stac-scout replay scout.manifest.json
```

Replay reports complete/partial/inconclusive comparison status plus confirmed and unresolved
missing/new Item IDs. A capped historical or current search is never promoted into false
confirmed drift.

## What this demo proves

```text
task semantics
→ cross-provider candidates
→ live Item evidence
→ asset selection evidence
→ resampling evidence
→ volume estimate or UNKNOWN
→ versioned manifest
→ completeness-aware replay
```

It does not claim that one post-fire window alone is a complete wildfire impact analysis.
24 changes: 24 additions & 0 deletions examples/wildfire-impact/request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"task": "assess wildfire impact around Lahaina after the August 2023 fire",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-156.72, 20.84],
[-156.64, 20.84],
[-156.64, 20.93],
[-156.72, 20.93],
[-156.72, 20.84]
]
]
},
"datetime": {
"start": "2023-08-09T00:00:00Z",
"end": "2023-08-20T23:59:59Z"
},
"data_type": "optical",
"required_measurements": ["nir", "swir22"],
"max_source_resolution_m": 20,
"target_crs": "utm",
"target_resolution_m": 20
}
Loading