Environment Configuration — Terrain Stacks
Real-terrain v2 combines a gap-free DEM base with finer DEM insets, sunlit and permanently-shadowed-region (PSR) colour, masks, and quality
layers. This guide covers catalogs, region requests (RealTerrain(body, lat_deg, lon_deg, size_m) or srb asset download terrain --lat --lon --size-m), deshading, download consent, and companion arbitration with the ephemeris sun.
For the fusion engine itself (blending, provenance, budgets) see Real Terrain Assets; for authoring catalog layers and v2 manifest sites see Adding Terrain Sites.
The target pair is Isaac Sim 6.1.0 and Isaac Lab 3.0.0. Terrain physics and renderer claims require runtime evidence; rasters and Isaac-free fixtures cover catalog and byte contracts. See Installation requirements and Real Terrain Assets.
Coverage is curated and limited. The shipped catalogs contain 19 Moon layers and two each for Mars and Earth. A region outside their footprints produces an empty plan: environments fall back to procedural terrain with a warning, while CLI downloads report an error. See Catalog status per body. Set
SRB_TERRAIN_CATALOG_DIRto use a custom or fixture catalog.
The catalog model
Cache and catalog compatibility
Named single-source site cache keys include effective patch geometry, ortho, and attribution; equivalent integer and floating-point geometry share a key. Old named-site keys are orphaned, while legacy serialization and v2 stack or region keys retain their contracts. Old bakes may need to be recreated.
SRB_TERRAIN_CACHE_ROOT overrides the default cache location. Checkouts use the SRB scenery cache; installed wheels use
$XDG_CACHE_HOME/srb/terrain, falling back to ~/.cache/srb/terrain when XDG is unset or relative. Raw archives are shared by content identity: CLI
cleanup with --raw or --all requires omitting the site argument. Site-specific baked cleanup remains available. Incomplete unpublished bakes can
be cleaned, but a corrupt published pointer remains an error that needs inspection.
On POSIX, different raw sources can download concurrently; requests for the same content wait for acquisition. Raw cleanup waits for active fetches and verification. Consent refusal or a size limit aborts the stack. Cached windows distinguish padding and resampling method and preserve nodata margins.
Catalog validation preserves the body/layers YAML shape and rejects unknown catalog or alignment keys, malformed footprints, and polar caps
outside (0, 90] (without checking polygon topology). Alignment offsets are dx_m, dy_m, and dz_m. Region coordinates normalize antimeridian
values and signed zero; target GSD must be positive and finite.
Colour fusion normalizes each integer source by its dtype maximum. Floating-point loaders must provide unit-scale values; photometric class does not specify scale or offset. Mixed stacks normalize sources before compositing.
Each per-body catalog (srb/terrain/catalog/<body>.yaml) pins approved data products, URLs, hashes, footprints, native GSD, licenses, priority, and
the curated half of the large-download consent gate. The resolver intersects footprints with a region and builds prioritized DEM, colour, mask, and
quality stacks for fusion. Preview a plan without moving a byte:
srb asset stack --body moon --lat -89.46 --lon 137.3 --size 2000
srb asset stack --body moon --lat -89.46 --lon 137.3 --size 2000 --json
srb asset stack reports the request’s --deshade flag; a site’s manifest can also enable deshading for its bake (see
Deshade).
There are two ways to consume the catalog:
- Declared-stack site: a
version: 2manifest entry names catalog layers indem_stack/color_stack; use the sameRealTerrain(..., site=...)andsrb asset download terrain <site>interfaces as v1. - Region request: no manifest entry; the resolver finds layers by footprint intersection.
Catalog status per body
| Body | Layers | Curated families |
|---|---|---|
| moon | 19 | pgda_ldem_83s_10mpp / pgda_ldem_80s_20mpp (LOLA polar DEM bases); lroc_nac_dtm_shackrdge02 / nobile03 / malapert02 / malapert03 (NAC DTMs); usgs_astro_haworth_sfs_dem_1m (Haworth SfS DEM); zenodo_sfs_a3clr06_connridge_dem_5m / zenodo_sfs_a3clr06_connridge_omos_5m / zenodo_sfs_a3clr02_haworth_dem_5m / zenodo_sfs_a3clr02_haworth_omos_5m (SfS A3CLR DEM + orthomosaic, Connecting Ridge and Haworth); lroc_shadowcam_dtm_faustini_6m + lroc_shadowcam_cmosaic_faustini01_20m (ShadowCam DTM + cmosaic); lroc_nac_roi_haworth_lo1_20m (NAC ROI); lroc_wac_emp_643nm_south_100m (WAC_EMP 643 nm colour); imbrium_ldam_50s_1000m (LOLA LDAM 1064 nm normal albedo, nominal 1000 m at the pole, cap:50S); pgda_lpsr_85s_60m (PGDA LPSR mask); lroc_nac_pole_south_cm065_p892s2250_1m + lroc_nac_pole_south_cm135_p892s2250_1m (NAC_POLE_SOUTH_CM band-1 tile P892S2250, one per subsolar-longitude epoch — reference_only: true, so resolvable only by explicit layer_id, never as bake input) |
| mars | 2 | usgs_astro_hirise_jezero_dtm_1m + usgs_astro_hirise_jezero_ortho_1m (HiRISE Jezero DTM + ortho) |
| earth | 2 | copernicus_glo30_dryvalleys_s78e161 (Copernicus GLO-30 polar); usgs_3dep_nm_southeast_x45y364_1m (3DEP 1 m non-polar) |
Named site: Jezero v2
The shipped manifest keeps the v1 jezero site and adds jezero_v2. The named v2 site is centered at (18.44, 77.44) with a 2,000 m medium patch.
Its declared stack names the pinned Mars catalog layers usgs_astro_hirise_jezero_dtm_1m (DEM base) and usgs_astro_hirise_jezero_ortho_1m (colour
base). The catalog records the DTM SHA-256 b710df2893d0c668e58ec6e4c3fffa4e1b8b1759b71fdb4c582dfe56ef479822 and the ortho SHA-256
4ceef4f3a1ceda63987ed66ccb0b387cfe0461d0bff5af8cc047b348502a1c58.
Use either consumption form with the same declared stack:
RealTerrain(body="mars", site="jezero_v2")
srb asset download terrain jezero_v2 --lod medium
Offline fixtures exercise named-site resolution and fusion using checked-in rasters; they do not validate the pinned HiRISE bytes.
Coverage is curated, not exhaustive. A v2 site whose declared base does not cover the footprint fails with
DeclaredBaseUnavailableError instead of falling back to v1; a region request yields an empty plan. LDAM is pinned as imbrium_ldam_50s_1000m: a detached PDS3 .LBL/.IMG bundle from the HTTPS-only imbrium provider, with
independent file hashes and sizes. Its cap:50S footprint is the inscribed extent, and its nominal 1000 m/pixel resolution is true at the pole.
WAC_EMP’s priority 3 keeps its 643 nm product ahead of priority-4 LDAM where both cover; consumers must tolerate the possible 643 nm/1064 nm spectral
seam. The Connecting Ridge P892S2250 band-1 tiles are pinned by epoch as reference_only: true comparison references; they cannot be used in a
bake. Other tiles remain unpinned because their large sizes require a site-specific decision. See Adding Terrain Sites → Adding a v2 source
layer for the authoring workflow to curate more layers.
Providers
Catalog provider names are registered in srb/terrain/sources/registry.py. Remote providers enforce host allowlists in their implementations;
examples:
| Provider | Body | Hosts | Auth |
|---|---|---|---|
uahirise | mars | hirise.lpl.arizona.edu, www.uahirise.org, uahirise.org | none |
copernicus_s3 | earth | copernicus-dem-30m.s3.amazonaws.com, copernicus-dem-90m.s3.amazonaws.com | none |
usgs_3dep | earth | prd-tnm.s3.amazonaws.com | none |
imbrium | moon | imbrium.mit.edu | none |
The imbrium provider accepts https only. Fetches re-check the allowed scheme and host on every redirect, so an HTTPS-to-HTTP downgrade is
rejected.
Providers use unauthenticated HTTP(S) GETs; imbrium requires HTTPS. Authenticated sources such as private buckets or API-key-gated endpoints are
unsupported. Existing Mars USGS products (CTX, HRSC-MOLA) need no new provider — the existing usgs_astro hosts already cover them.
Region requests
from srb.assets.scenery import RealTerrain
terrain = RealTerrain(body="moon", lat_deg=-89.66, lon_deg=0.0, size_m=2000.0)
lat_deg / lon_deg / size_m are all-three-or-none — setting any one without the others is a validation error naming the missing field(s) —
and mutually exclusive with both site= and dem_path= (and with the patch-override fields patch_size_m/patch_center_xy_m: a region’s own
size_m and resolved center define the bake footprint). lod maps through; size_m may be at most 8000 m (MAX_REGION_SIZE_M — tile larger areas
as multiple requests).
Because these are plain numeric fields (not a nested config), the intent is that they be CLI-addressable on any env whose scenery is a RealTerrain
via Hydra’s dotted-override syntax:
srb agent teleop -e _ground \
env.scenery.lat_deg=-89.66 env.scenery.lon_deg=0.0 env.scenery.size_m=2000
The ground-task Hydra registration exposes these fields in the structured env.scenery mapping, so ordinary dotted overrides work without a +
prefix. The resolver constructs RealTerrain and derives body from env.domain when env.scenery.body is omitted. An explicit body is useful
for a task whose domain is not the requested planetary body:
srb agent teleop -e _ground \
env.domain=moon env.scenery.body=moon \
env.scenery.lat_deg=-89.66 env.scenery.lon_deg=0.0 env.scenery.size_m=2000
The constructor and the dedicated srb asset download terrain --lat --lon --size-m / srb asset stack --lat --lon --size commands remain equivalent
entry points. All three region coordinates are still required together, and the normal Hydra struct validation rejects unknown scenery keys.
Region identity: the slug
A region request’s cache identity is a deterministic, machine-independent slug used everywhere a manifest site’s name would be:
region_{body}_{lat_deg:+08.4f}_{lon_deg:+09.4f}_{int(round(size_m))}m
# e.g. region_moon_-89.6600_+000.0000_2000m
The request’s fields themselves are normalized before the slug (or anything else) reads them, so two requests within the same quantum are genuinely the same region — same fields, same cache entry, same bake:
lon_degis wrapped to[-180, 180)(solon=180andlon=-180are one region), and signed zero collapses to0.0;lat_degandlon_degare rounded to1e-4degrees (≈3 m on the Moon) — requests differing only inside that quantum share one cached region;size_mis rounded to whole metres.
Changing these widths changes region slugs and orphans existing cache entries.
Bodies and canonical CRSs
Moon, Mars, and Earth are supported. Requests use each body’s canonical polar and geographic coordinate reference systems (CRSs):
| Body | South-polar | North-polar | Geographic |
|---|---|---|---|
| moon | IAU_2015:30135 | IAU_2015:30130 | IAU_2015:30100 |
| mars | IAU_2015:49935 | IAU_2015:49930 | IAU_2015:49900 |
| earth | EPSG:3031 | EPSG:3413 | EPSG:4326 |
Mars uses the IAU 2015 sphere radius 3396190.0 m; Earth uses WGS84 (6378137.0 m). CRS matching accounts for projection scale. User-supplied DEMs
with a different projection are reprojected rather than treated as a canonical grid.
Body-aware, non-polar-capable resolution
Requests at |lat_deg| >= 60° use the body’s canonical polar CRS; others use a local stereographic CRS centered on the request. Local CRS
construction rejects the poles, which use the canonical polar CRS instead. Environments fall back to procedural terrain and the CLI reports an error.
Footprints: the bbox: form
A catalog layer’s footprint field (see Adding Terrain
Sites) now accepts a third shorthand alongside
cap:<lat><N|S> and WKT POLYGON(...)/MULTIPOLYGON(...) in projected metres:
bbox:<lonmin>,<latmin>,<lonmax>,<latmax>
— a plain geographic-degrees footprint, body-agnostic and independent of whatever projected CRS the region happens to resolve into. This is the form non-polar (and most Mars/Earth) layers are expected to use, since authoring a WKT polygon in a per-region local stereographic CRS that doesn’t exist until request time is impractical. Rules, enforced at schema load and at footprint-containment time:
lonmin/lonmaxaccept the full[-360, 360]pre-normalization range — the dominant convention for planetary product metadata (LOLA/HRSC/CTX 0–360° east longitude) works unmodified — and are normalized to[-180, 180)once, at parse time, before any containment check runs.lonmin > lonmaxafter normalization is a deliberate antimeridian wrap (the box spans ±180°), not an error — containment islon >= lonmin or lon <= lonmaxin that case, mirroring the region-slug’s own lon handling.latmin <= latmaxis enforced (unlike lon, an inverted latitude band has no valid meaning):latmin > latmaxraises apydantic.ValidationErrornaming the footprint string, at catalog-load time, before any byte moves.- Containment against a request is evaluated by projecting each sample point back to lat/lon (
xy_to_latlonin the region’s own resolved CRS, whatever that is — canonical polar or local stereographic) and testing the degree box directly, sobbox:footprints work identically in every body-aware CRS from the section above.
cap: and WKT-in-projected-metres are unchanged; WKT stays usable only when the catalog author and the region resolver agree on a shared canonical
projected CRS (effectively: polar layers only, since a non-polar region’s CRS is generated fresh per request and can’t be known ahead of time when the
catalog entry is authored).
What happens when a region can’t resolve
An empty DEM plan — any request whose footprint no curated layer covers (most requests today, since coverage is narrow — see Catalog status per
body), or a request against a body/region with no catalog coverage at all — raises RegionUnresolvedError inside the bake
path. The two consumers treat it differently, on purpose:
- Environments (
RealTerrainasenv.scenery): the existing terrain degrade ladder catches it and falls back to the procedural terrain, with a one-time warning naming the region slug and the reason. Training keeps running; the terrain just isn’t real. - CLI (
srb asset download terrain --lat ...): prints the same reason and exits 1 — a download command has no procedural fallback by design: a download that cannot resolve should say so, not silently bake noise. When the body’s loaded catalog really has zero layers, the error is followed by a note naming the catalog file and the dormancy state.
CLI
# Arbitrary region (mutually exclusive with a positional site target,
# --all, and the site-only flags --patch/--patch-size/--center/--no-ortho):
srb asset download terrain --lat -89.66 --lon 0.0 --size-m 2000 \
[--body moon] [--lod medium] [--deshade] [--force]
# Preview what a region would resolve to (moves no bytes):
srb asset stack --body moon --lat -89.66 --lon 0.0 --size 2000 [--deshade]
# Assess without baking (doctor/info know region-derived cache entries):
srb asset doctor terrain [--deshade]
The region download routes through the exact same bake_or_load path the envs use, so consent, caching, and provenance all apply unchanged. A
remediation command printed by doctor/availability (download_command) reproduces the request faithfully — including --deshade when the assessment
was deshade-keyed, since a deshaded bake is a different cache entry (below).
Per-env location variety
Region requests (only region requests — a curated site or a local dem_path have a fixed footprint) can fan out into K distinct patches, one
baked USD per patch, distributed across environments by the Isaac Lab clone planner instead of every env sharing the same terrain:
from srb.assets.scenery import RealTerrain
# K=8 patches: index 0 is the requested center verbatim; the other 7 are
# deterministic seeded offsets within a 3000 m disk around it.
terrain = RealTerrain(
body="moon",
lat_deg=-89.66,
lon_deg=0.0,
size_m=2000.0,
num_locations=8,
location_spread_m=3000.0,
)
# Explicit centers instead of derived offsets (all share size_m/lod/deshade):
terrain = RealTerrain(
body="moon",
size_m=2000.0,
locations=[(-89.66, 0.0), (-89.40, 15.0), (-89.80, -20.0)],
)
Pre-bake the same set from the CLI (serial, same bake_or_load path, same consent/caching/provenance rules as a single-location download):
srb asset download terrain --lat -89.66 --lon 0.0 --size-m 2000 \
--num-locations 8 --location-spread-m 3000
Each line printed is <slug>: <path>, one per baked location, in derivation order. --num-locations/--location-spread-m are rejected (exit 2) off
the --lat/--lon/--size-m region form, exactly like --patch-size/--center; --num-locations below 1 is also exit 2. A
RegionUnresolvedError on any location prints that location’s slug and stops the run — locations after the failing one are never attempted, and any
already-baked predecessors are kept (partial completion, not all-or-nothing).
Semantics
| Aspect | Behavior |
|---|---|
| Primary patch | Index 0 is always the requested (lat_deg, lon_deg) center verbatim (or locations[0] for the explicit-list form). Companions, the SimForge augment layer, and any other single-path reader use RealTerrain.primary_baked_usd_path, which anchors to this patch. |
| Derivation | Requests 1..K-1 come from numpy.random.default_rng([905, seed]) (a fixed salt decoupling this stream from every other consumer of seed), sampled uniformly in a disk of radius location_spread_m (r = location_spread_m · √u) in the request’s own resolved projected CRS (canonical polar-stereographic near the poles, local stereographic elsewhere — see Bodies and canonical CRSs). location_spread_m defaults to size_m when omitted. |
| Prefix-stability | The RNG stream does not depend on K, so raising num_locations (e.g. 4 → 8) keeps the first 4 derived slugs — and their cache entries — unchanged; it only appends new ones. |
| Slug uniqueness | After the usual 1e-4 deg / whole-metre normalization, the K requests must resolve to K distinct slugs. A collision (spread too small relative to the quantum, or duplicate entries in an explicit locations list) raises RegionInvalidError naming the duplicate slugs and suggesting a larger location_spread_m or de-duplicating locations — never a silent dedupe or re-jitter. |
| Any latitude | The offset math runs in the request’s own projected CRS (canonical polar-stereographic near the poles, local oblique stereographic elsewhere — see body-aware resolution above), so neither derived nor explicit centers are restricted to the polar band. |
locations vs num_locations | Mutually exclusive: locations fixes K to its own length and requires size_m (it has no single center to pair with lat_deg/lon_deg); passing both locations and num_locations != 1, or locations together with a lat_deg/lon_deg center, is a validation error. |
| Companions | A region request has no curated companions regardless of K (unchanged from the single-location case) — they attach only for a curated site. |
K==1 (the default) uses the single-patch behavior: same UsdFileCfg spawner, cache entries, and slugs. K>1 instead spawns a genuine
MultiAssetSpawnerCfg (func=spawn_multi_asset_compat) at the env-scoped prim path, which Isaac Lab’s clone planner distributes one variant per
environment.
Deshade (illumination-corrected colour)
Real sunlit colour mosaics have the sun baked into them: topographic shading from the capture-time illumination fights the renderer’s own lighting.
deshade=True corrects for this at fusion time — for each sunlit colour layer, the engine models a hillshade of the fused DEM at that layer’s
catalogued capture illumination (sun_azimuth_deg/sun_elevation_deg on the catalog layer) and divides it out, mean-preserving (the layer’s overall
brightness does not shift) and NaN-safe (nodata holes pass through untouched). Rules:
- PSR colour layers are never deshaded — a permanently shadowed region has no capture-time sun to divide out.
- A sunlit layer without catalogued sun angles is left un-deshaded, with a warning naming it that lands in the bake’s
meta.jsonfusionwarnings— never a silent skip. - If no fused DEM is available to model hillshade from, colour is left un-deshaded with a warning.
Three knob surfaces, one precedence rule:
| Surface | Form |
|---|---|
| Site manifest | deshade: true on the site entry (srb/terrain/manifest.yaml) |
| Python | RealTerrain(..., deshade=True) |
| CLI | --deshade on srb asset download terrain / srb asset stack / srb asset doctor |
Precedence is manifest or request: a request-level deshade=True can only turn deshading on; it can never disable a manifest-declared
deshade: true. The effective flag is folded into the v2 cache key (any knob that changes baked pixels must be), so deshaded and non-deshaded
bakes of the same region/site coexist as distinct cache entries; the default False keeps every pre-existing cache key byte-identical.
v1 sites cannot deshade. A v1 (single-source sources.dem) site has no fusion engine in its bake path, so deshade=True there is not silently
inert — it raises (DeshadeUnsupportedError), and the CLI checks the same manifest fact before a single byte is fetched rather than after the
whole DEM download.
Consent
A v2 catalog layer whose estimated fetch exceeds 1 GiB needs both the layer’s curated allow_large_download: true and the operator’s
SRB_TERRAIN_LARGE_OK=1 environment variable at fetch time (check_layer_consent, an AND — env-var only, never an interactive prompt). Region
requests add no second consent mechanism; the same gate governs every byte the region path moves. See allow_large_download +
SRB_TERRAIN_LARGE_OK for the full rules and why srb asset stack’s printed “consent required” line is only a descriptive preview.
Companions and the ephemeris sun
A curated real-terrain site can carry companion products — a sky dome, a lighting rig (possibly ephemeris-baked; see Terrain
lighting), and rock sets. The environment path attaches them automatically: BaseEnvCfg._add_scenery calls
attach_companions() whenever the resolved scenery is a RealTerrain with attach_companions_enabled=True (the default; set it False to disable
attachment).
Some shipped companion catalog entries are placeholders, so those products may be unavailable. If a site’s companion set cannot be built, the whole set is dropped with a warning and the environment continues without companions.
Both a companion lighting product and an enabled env.ephemeris want to own “what lights this scene”, so attachment is arbitrated
(srb.terrain.companion_scene.arbitrate_companion_scene) under a fixed precedence. Every suppression warns once, naming both conflicting knobs:
| # | Condition | Outcome |
|---|---|---|
| 1 | env.ephemeris.enabled and drive_sunlight | The ephemeris sun owns lighting: the companion lighting product is suppressed (warn-once). If drive_skydome is also set, the companion sky is suppressed too. Companion rocks still attach. |
| 2 | Else, the companion set contains lighting | The companion owns the scene sun: scene.sunlight is set to None and the four static sunlight randomizers (randomize_sunlight_*) are skipped (warn-once when any were configured) — scene.lighting and scene.sunlight are mutually exclusive. A manifest lighting: "ephemeris" site under an env without env.ephemeris.enabled gets its baked ephemeris preset this way. |
| 3 | The companion set contains sky | The companion sky replaces the domain-default skydome and randomize_skydome_orientation is nulled (deterministic curated sky) — unless the env explicitly configured a non-default skydome string (e.g. env.skydome=high_res, which wins over the companion sky) or explicitly disabled the skydome (env.skydome=null/false — an operator disable also wins; the companion must not silently re-add a dome). |
Additional rules:
- Region terrains have no curated companions (there is no manifest entry to declare them), so a region request attaches nothing — silently:
absence is not a conflict, nothing warns.
env.ephemerisis the way to get a real sun on a region patch; a manifestlighting: "ephemeris"is unreachable for region requests until a manifest entry exists.
Illumination sidecar
A baked patch can carry a precomputed illumination sidecar (illumination.npz, schema srb_illum/2) alongside its terrain.usd — a separate,
out-of-band artifact produced by srb ephemeris import, not a bake input (it is not part of the CacheKey). RealTerrain.illumination_product_path
exposes it (derived from the primary/index-0 patch only — see the per-env location variety limits above for what that means under num_locations > 1), and srb/core/mdp/illumination.py’s masked-spawn term and illumination_fraction_at reward helper consume it. See Illumination
Products for the full schema, importer, and consumer reference.
Augmentation database (srb_augdb/1)
Terrain bakes may include a deterministic augmentation.npz sidecar containing synthetic crater and rock placements. The sidecar is generated from
the baked patch and can be read with srb.terrain.augmentation.database.load_augmentation_db(baked_dir); a missing sidecar returns None, while
invalid data raises ValueError. RealTerrain.augmentation_db_path refers to the primary patch’s sidecar.
The srb_augdb/1 schema stores craters as (N, 4) arrays of x_m, y_m, radius_m, depth_m, and rocks as (N, 6) arrays of x_m, y_m, z_m, scale, yaw_rad, asset_idx. Coordinates are patch-local. Placements are deterministic for the same seed, terrain, and preset. Steep terrain can reduce
the number retained; requested and kept counts are recorded in bake metadata. Earth has no default augmentation; Moon and Mars default to rocks, while
crater stamping requires an explicit crater preset and the augment_stamp option. Synthetic craters are a documented terrain profile, not a physical
crater model.
Explicit rock scatter — augment="database"
RealTerrain.augment supports "none" (default), "simforge", and "database". The database mode places rocks at the recorded transforms, with
augment_max_rocks limiting the number used. Missing or empty placement data produces a warning and leaves the terrain usable. "simforge" retains
its existing generated-scatter behavior.
Synthetic super-resolution layer slot
The catalog schema’s radiometry enum includes a "synthetic" class, reserved for a future super-resolution or model-generated DEM/color product.
The resolver treats it as a lowest-priority, opt-in slot:
- Skipped by default.
radiometry == "synthetic"layers never become candidates at all in_build_sorted_candidatesunless the request explicitly admits them — a catalog with one synthetic DEM layer and one real DEM layer resolves to the real one only, no warning needed (there is nothing wrong to warn about). - Strictly last when admitted. The resolver’s total sort key is
(is_synthetic, priority_class, native_gsd_m, layer_id)— a synthetic layer sorts after every non-synthetic candidate regardless of its ownpriority_class/native_gsd_m. Even a syntheticpriority_class=1, native_gsd_m=0.5layer loses to a realpriority_class=9layer. - Declared-stack sites admit synthetic layers implicitly. A v2 site’s manifest-declared
dem_stack/color_stackentries are matched bylayer_id, not filtered byradiometry— naming a synthetic layer in a manifest is explicit authorial intent, so it is never skipped the way an unrequested footprint-search candidate would be. The opt-in gate only matters for footprint-searched (resolve_stacks) and declared-site mask/quality/PSR-color candidates.
Opt-in surface. RegionRequest.allow_synthetic: bool = False and TerrainSpec.allow_synthetic: bool = False (threaded through exactly like
deshade). The flag is deliberately not part of the cache-site slug (a region’s identity string), but it is pixel-changing once a catalog
ships a synthetic layer, so CacheKey.hash12() appends "synthetic=1" to the hashed material only when the flag is True — the same append-only
“inert default” precedent deshade=1 established. allow_synthetic=False keeps hash12() byte-identical to every existing golden hash; the default
plan for every existing catalog is unaffected either way, since none ships a synthetic layer.
A region-form TerrainSpec.allow_synthetic=True whose region sub-spec disagrees (region.allow_synthetic=False) raises at spec-construction time —
region terrain specs read the effective flag from RegionRequest.allow_synthetic, so a spec-level flag that the region does not also carry would
silently do nothing, which the boundary check refuses to allow.
Scope. The slot is schema + resolver plumbing only. No shipped catalog carries a synthetic layer; no super-resolution model is integrated. This is unrelated to the augmentation database’s rock scatter, which is wired explicitly via
augment="database"— no synthetic-radiometry product feeds rock/crater placement today, and nothing here changes with that landing.
Current limits
- Catalog coverage is limited to the products listed in Catalog status per body. Uncovered requests use procedural terrain in environments and fail on the CLI.
- Catalog sources are public and unauthenticated. A source requiring an API key or private-bucket credentials cannot be added with the current providers.
cog_remoteis a compatibility label: SRB downloads and verifies the full source before reading a local window. First use needs space for that source; the large-download consent gate applies where configured.- Integer colour rasters currently have no separate validity-mask channel. For cross-CRS reads without source nodata metadata, out-of-footprint pixels may be read as zero. Avoid interpreting those pixels as valid colour data.
- Companion attachment is all-or-nothing per site.
- Region
num_locationsbakes every requested patch serially, even when a run uses fewer environments. The selected patch for environmentiisi % num_locations; stacked scenes use the first patch only.