# Derkachi reference C6 tile catalog — fixture seeding **AZ-777 Phase 2 deliverable.** Seeds the parent-suite `satellite-provider` DB with the satellite tiles the C6 reference catalog needs for the Derkachi replay tests (`test_ac3_within_100m_80pct_of_ticks` on AC-4 + `test_az699_real_flight_validation_emits_verdict_and_report` on AC-5). ## What this folder contains | File | Purpose | |------|---------| | `bbox.yaml` | bbox + zoom levels + actual flight extent + imagery source metadata + license attribution + chunking strategy | | `seed_region.py` | Python script that submits `POST /api/satellite/request` to satellite-provider for each (zoom × chunk) and polls until completion | | `README.md` | this file | ## Prerequisites 1. **Running satellite-provider.** Typically the Jetson e2e harness via `docker-compose.test.jetson.yml` (services `satellite-provider` + `satellite-provider-postgres`). Verify it's up and healthy: ```bash ssh jetson-e2e "docker ps --filter name=satellite --format 'table {{.Names}}\t{{.Status}}'" ``` 2. **`SATELLITE_PROVIDER_URL`** in `.env.test` (already covered by the AZ-777 Phase 1 wiring). 3. **`SATELLITE_PROVIDER_API_KEY`** — a valid HS256 JWT signed with the same `JWT_SECRET` the satellite-provider validates against. Mint with: ```bash export SATELLITE_PROVIDER_API_KEY="$(python scripts/mint_dev_jwt.py)" ``` 4. **Google Maps Platform API key** on the satellite-provider side (env `GOOGLE_MAPS_API_KEY` / config `MapConfig__ApiKey`). The satellite-provider uses this to actually download the tiles from Google Maps. The seed script does NOT need this key — it only triggers the producer's async download pipeline. ## Quick start ```bash # from gps-denied-onboard repo root, with satellite-provider running on Jetson: export SATELLITE_PROVIDER_API_KEY="$(python scripts/mint_dev_jwt.py)" python tests/fixtures/derkachi_c6/seed_region.py ``` Expected runtime: ~5-15 minutes for the full spec bbox (8 region calls × ~30-60s each + inventory verification). ## Flags ``` --bbox-config PATH override bbox.yaml location --env-file PATH override .env.test fallback location --output-summary PATH write a JSON summary for downstream consumers --dry-run validate config + plan without submitting --right-sized-flight use the actual ~1 km^2 flight extent (98% fewer tiles) --skip-poll submit + return; don't wait for terminal status --skip-inventory-verification skip the final coverage check ``` ## bbox sizing — important `bbox.yaml` ships TWO bboxes: * `bbox`: per AZ-777 spec — covers ~11.1 × 7.14 km (~80 km²) of the Derkachi village area. **~4570 tiles z15-z18 (~57 MB)**. Default seeding target. * `actual_flight_extent`: the real Derkachi flight footprint per `data_imu.csv` — only ~254 × 457m (~0.12 km²) centered at (50.082, 36.110). **~60 tiles z15-z18 (~1 MB)** if seeded right-sized via `--right-sized-flight`. The spec bbox is ~300× larger than the actual flight extent. The spec sizing is intentional generality — operators can fly any route within the box without re-seeding. The right-sized mode is appropriate when only the specific Derkachi clip needs coverage (e.g., CI test runs). ## Imagery source — IMPORTANT licensing note AZ-777 was originally specced with **CARTO Voyager Basemap (CC-BY-3.0)** as the upstream imagery source. The 2026-05-22 black-box probe of the running satellite-provider revealed the actual upstream is **Google Maps satellite layer** (`mt0..mt3.google.com/vt/lyrs=s`). The AZ-777 spec was amended to reflect this reality (see Risk 4 in `_docs/02_tasks/todo/AZ-777_derkachi_c6_reference_fixture.md`). **Operators MUST propagate the attribution string `"Imagery © Google"` to any end-user-visible context** that incorporates tiles seeded by this script. Per `bbox.yaml::license`. **Dev/research use is approved. Production deploy requires either:** 1. Google Maps Platform licensing review for the offline-cache use case (the C6 reference dataset is a long-lived stored cache, which Google Maps ToS may restrict), OR 2. A parent-suite ticket to add a true CC-BY satellite imagery provider to satellite-provider (candidates: Esri World Imagery, Mapbox satellite, Sentinel-2 via Copernicus). TBD; not in scope for AZ-777. ## Re-seeding (after a satellite-provider DB wipe) The script is **idempotent and safe to re-run**: * Each invocation generates fresh region UUIDs, so each run creates a new set of region records on the producer side. * The producer's tile-storage layer dedups via UPSERT on (zoom, x, y), so tiles already downloaded from Google Maps are NOT re-fetched — they're counted as `tilesReused` instead. * Re-runs are cheap (just the region-tracking overhead) when the DB is warm. To verify the catalog is populated without re-running the full seed, query inventory directly: ```bash # inside the satellite-provider docker network: docker run --rm --network gps-denied-onboard_default curlimages/curl:8.10.1 \ -sk -X POST -H "Authorization: Bearer $SATELLITE_PROVIDER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"tiles":[{"z":18,"x":157497,"y":89000}]}' \ https://satellite-provider:8080/api/satellite/tiles/inventory ``` ## Cost expectations Per the 2026-05-22 probe baseline (200m @ z18 = 9 tiles, ~13 KB/tile, ~5s end-to-end): | Mode | Tile count | DB size | Wall time (cold) | Wall time (warm DB) | |------|------------|---------|------------------|---------------------| | Spec bbox (~80 km²) | ~4570 | ~57 MB | ~5-15 min | ~30s (reuse) | | Right-sized (~1 km²) | ~60 | ~1 MB | ~1-2 min | ~10s (reuse) | Google Maps API cost per tile depends on the satellite-provider operator's Maps Platform pricing tier. The seed script does NOT bill — the producer's Google Maps account does. ## Failure modes | Exit code | Meaning | Likely cause | |-----------|---------|--------------| | 71 | config file missing / malformed | `bbox.yaml` corrupted or wrong path | | 72 | required env var missing | `SATELLITE_PROVIDER_URL` or `SATELLITE_PROVIDER_API_KEY` not set | | 73 | satellite-provider unreachable | Service down, wrong URL, or TLS handshake failed (try `SATELLITE_PROVIDER_TLS_INSECURE=1`) | | 74 | region request rejected | HTTP 4xx (auth, validation) or 5xx (producer crash); see stderr for HTTP body | | 75 | one or more regions failed | Background processing failed — usually a Google Maps API quota / key issue on the producer side. Check `docker logs gps-denied-e2e-satellite-provider` | | 76 | inventory verification mismatch | < 95% of expected tiles present; re-run to retry, or investigate producer logs | ## Cross-references * AZ-777 spec: `_docs/02_tasks/todo/AZ-777_derkachi_c6_reference_fixture.md` * AZ-777 Phase 1 (the wiring that makes this script callable): completed cycle 3 batch 105 * AZ-808 (parent-suite): strict validation for region-request endpoint — when this lands, malformed `seed_region.py` invocations will fail with RFC 7807 ValidationProblemDetails instead of silent zero-coercion; coordinate any consumer-side changes with that release * AZ-812 (parent-suite): rename `RequestRegionRequest.{Latitude, Longitude}` → `{Lat, Lon}` for OSM consistency — when this lands, `seed_region.py` must be updated to send `lat`/`lon` instead of `latitude`/`longitude` * satellite-provider Region API contract: today informally documented in `../../../../satellite-provider/_docs/02_document/modules/common_dtos.md::RegionRequest` + `system-flows.md` Flow F2; formal `region-request.md` contract will be published as part of AZ-808