Scoping Rules for Spatial Products
Scoping rules are the executable contract that decides what a spatial product is allowed to contain, publish, and expose before it ever reaches a consumer — the admission gate that keeps a federated geospatial estate from drifting back into a monolith.
Enterprise spatial platforms require deterministic scoping mechanisms to prevent architectural bleed, enforce domain autonomy, and guarantee predictable product delivery. When an organisation moves off a monolithic geodatabase toward domain-aligned ownership, scoping rules establish the immutable boundary between what a domain team controls and what the shared platform guarantees. This guide sits inside the Geospatial Data Mesh Fundamentals reference and assumes you have already separated your estate into autonomous domains as described in Spatial Domain Boundary Design. Where boundary design answers who owns this geometry, scoping rules answer under exactly what coordinate reference system, extent, resolution, and access contract may this product be published — the difference between a soft organisational convention and a gate that rejects a non-conforming manifest at publication time. The most granular field-by-field reference for those gates lives in Defining scoping rules for enterprise spatial products.
Figure — Scoping rules as policy-as-code: a manifest must clear CRS, extent, and resolution gates before it can publish to the mesh.
Architectural Boundaries & Design Rationale
Scoping rules exist because spatial coupling is silent. Two domains can share an EPSG code, a tile matrix set, or a column name and appear interoperable while quietly accumulating dependencies that fail only under reprojection, rescaling, or topology repair. A monolithic geodatabase masks this by forcing one CRS and one schema registry on everyone; a federated mesh removes that crutch, so the platform must replace implicit agreement with an explicit, machine-checked contract. A scoping rule is that contract expressed as policy-as-code: a manifest declares its coordinate reference system, spatial extent, resolution, geometry type, and service-level targets, and the platform admits the product only if every declared field clears a gate.
The failure modes this pattern prevents are concrete. Extent bleed occurs when a domain publishes geometry outside its assigned bounding box — a hydrology domain emitting features in a neighbouring catchment — which corrupts federated query results and lineage. Resolution leakage occurs when a sub-metre raster is published into a contract that consumers expect to be coarse, breaking both bandwidth budgets and, frequently, data-classification rules. CRS drift occurs when a product silently changes projection between versions, so downstream joins that assumed EPSG:4326 now misalign by hundreds of metres. Schema coupling occurs when a consumer reaches past the published API into a domain’s internal geometry types. Scoping rules close each of these by making the conforming path the only path to publication.
Because scoping is enforced at admission rather than at read time, it composes cleanly with the rest of the mesh. The routing layer described in the Federated Ownership & Routing Architecture trusts that any product reaching it has already cleared its CRS and extent gates, so cross-domain routing strategies can dispatch on declared metadata without re-validating geometry. The productization discipline from Product Thinking for GIS Datasets supplies the SLA fields a scoping rule binds, and Metadata Cataloging for Raster/Vector supplies the index those declarations are written into. Scoping is the gate; those capabilities are the systems on either side of it.
Specification & Contract Reference
A spatial product manifest is the unit a scoping rule evaluates. Every field below is mandatory; a missing or out-of-range field is a hard rejection, never a warning. CRS identifiers use EPSG codes, extents are expressed in the product’s declared CRS, and resolution is metres-per-pixel for raster or coordinate precision (decimal places) for vector.
| Manifest field | Type | Constraint / gate | Example |
|---|---|---|---|
domain |
string | Must match an owned domain in the boundary registry | hydrology |
crs |
string | Must be in the domain CRS allowlist | EPSG:4326 |
extent_bbox |
float[4] | Must be fully contained in the domain’s assigned extent | [5.8, 47.2, 10.5, 55.1] |
geometry_type |
enum | One of point|line|polygon|raster; immutable across minor versions |
polygon |
resolution |
float | <= domain max for raster; >= declared precision for vector |
10.0 (m/px) |
version |
string | v<semver>-crs:<epsg>-res:<n>m; CRS or resolution change forces a major bump |
v1.2.0-crs:EPSG:4326-res:10m |
max_query_latency_ms |
int | Bound to the published SLA; enforced at the gateway | 200 |
refresh_frequency_hours |
int | Freshness contract surfaced in the catalog | 24 |
classification |
enum | open|internal|restricted; gates resolution and consumer role |
internal |
The versioning convention is load-bearing. A string like v1.2.0-crs:EPSG:4326-res:10m encodes the two attributes that most often break consumers — projection and resolution — directly in the identifier, so a change from EPSG:4326 to EPSG:3857 or from 10m to 1m is forced to a new major version rather than smuggled into a patch. The geometry contract carried in geometry_type and the per-tile schema are owned upstream of routing by Schema Contracts for Vector Tile Data; a scoping rule references that contract rather than redefining it, which keeps a single source of truth for what fields a tile may carry.
Production Implementation
Scoping is enforced at three layers — routing admission, catalog registration, and access evaluation — and each layer must be idempotent (re-applying the same manifest yields the same state, never a duplicate) and zero-trust (no request is admitted on network position alone).
The routing layer rejects any request whose declared domain and CRS headers do not match an authorised destination. This is the same gateway discipline covered in API Gateway Mapping for GIS Services, applied here as a scoping gate. Note the explicit deny route — anything not matching the domain header returns HTTP 400 rather than falling through to a default backend.
# istio-virtualservice-scoping.yaml — applied via GitOps for idempotent reconciliation
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: spatial-domain-router
namespace: platform-gateway
spec:
hosts:
- api.spatial-platform.internal
http:
- match:
- headers:
x-spatial-domain:
exact: "hydrology"
x-crs-code:
exact: "EPSG:4326"
route:
- destination:
host: hydrology-processor.hydrology.svc.cluster.local
port:
number: 8080
headers:
request:
remove: ["x-geometry-type"] # strip internal type to prevent implicit schema coupling
- match:
- uri:
prefix: "/"
fault:
abort:
httpStatus: 400 # zero-trust default-deny: unmatched scope is rejected at the edge
percentage:
value: 100
route:
- destination:
host: hydrology-processor.hydrology.svc.cluster.local
port:
number: 8080
Catalog registration promotes a raw asset to a published product only after the manifest clears schema and extent validation. Driving it through ArgoCD makes the operation idempotent: re-syncing the same revision reconciles to the same catalog entry instead of creating a duplicate during a pipeline retry or network partition.
# argocd-catalog-sync.yaml — declarative, idempotent product registration
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: catalog-sync-hydrology
spec:
project: data-mesh
source:
repoURL: https://git.platform.internal/spatial-catalogs.git
targetRevision: main
path: hydrology/v1.2.0-crs-EPSG-4326-res-10m
plugin:
name: spatial-catalog-validator
env:
- name: VALIDATE_SCHEMA
value: "iso-19115-3" # metadata schema compliance
- name: ENFORCE_EXTENT
value: "true" # reject geometry outside domain bbox
- name: ENFORCE_IDEMPOTENCY
value: "true"
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- RespectIgnoreDifferences=true
destination:
server: https://kubernetes.default.svc
namespace: spatial-catalog
Access evaluation enforces the resolution and classification gates at request time. The following OPA/Rego policy denies by default, admits only when the consumer’s role matches the product’s domain role, confirms the requested bounding box stays inside the product extent, and blocks sub-metre raster access without an explicit approval grant.
# scoping.rego — default-deny spatial extent and resolution policy
package spatial.access
import rego.v1
default allow = false
allow if {
# consumer role must match the product's domain clearance
input.user.roles[_] == input.resource.domain_role
# requested bbox must stay inside the published product extent
input.request.bbox.latitude_max <= input.resource.max_lat
input.request.bbox.latitude_min >= input.resource.min_lat
# high-resolution rasters require an explicit grant
resolution_authorized
}
# sub-metre rasters need an explicit approval; coarser data is allowed
resolution_authorized if {
input.resource.resolution_meters >= 1.0
}
resolution_authorized if {
input.user.approvals[_] == "high-res-spatial"
}
Compile and distribute the policy from a central registry, and evaluate it in the service-mesh sidecar so every product endpoint enforces the same gate. Align denial responses with the OGC API - Features specification so consumers receive a standard, machine-readable error rather than an opaque 403.
Diagnostic Runbook
When a product fails to publish or a consumer is unexpectedly denied, work the gates in admission order — header propagation first, then registry sync, then policy, then artifact and SLA.
- Confirm header propagation. A
404on a spatial endpoint almost always means thex-spatial-domainorx-crs-codeheader never reached the gateway. Inspect the route table withkubectl get vs -n platform-gateway -o yamland replay the request with the headers set explicitly viacurl -H "x-spatial-domain: hydrology" -H "x-crs-code: EPSG:4326". A 400 here confirms the default-deny route fired because the headers did not match. - Verify catalog sync state. A registration that never appears means the validator rejected the manifest or the sync stalled. Run
argocd app get catalog-sync-hydrologyand read thespatial-catalog-validatorpod logs; a schema or extent failure halts promotion by design. - Re-run the extent gate locally. Reproduce an extent rejection before touching the policy:
ogrinfo -so -al product.gpkgreports the layer envelope, which you compare againstextent_bboxin the manifest. Geometry outside the declared box is the root cause, not the gateway. - Evaluate the access policy offline. For a
403, capture the OPA input and runopa eval -i input.json -d scoping.rego 'data.spatial.access.allow'. Afalseresult with a matching role usually means the requested bbox exceededmax_lat/min_lator the consumer lacked thehigh-res-spatialapproval. - Check version and CRS alignment. If consumers report misaligned joins, compare the
versionstrings: a silent CRS or resolution change should have forced a major bump. Mismatchedcrs:segments between producer and consumer versions are the signal. - Validate artifact integrity. Before blaming scope, confirm the published artifact matches what was registered — verify the signature with
cosign verifyand the manifest checksum, so a corrupted upload is not misread as a policy denial. - Trace an SLA breach to a layer. If
max_query_latency_msis exceeded, trace the request across compute nodes and inspect spatial index health (pg_stat_user_tablesfor fragmentation) before scaling — an unmaintained index, not insufficient capacity, is the common cause.
SLA Targets & Performance Baselines
Scoping rules bind these targets to the manifest so the gateway and observability stack enforce them rather than treating them as documentation. Tie alert thresholds to product SLAs, not to generic infrastructure metrics.
| Metric | Target | Alert threshold | Remediation action |
|---|---|---|---|
| Manifest admission latency | < 2 s | > 5 s for 3 consecutive syncs | Inspect validator pod; check schema registry connectivity |
| Query latency (p95) | <= max_query_latency_ms (e.g. 200 ms) |
p95 > target for 5 min | VACUUM ANALYZE vector store; scale read replicas |
| Extent-violation rejections | 0 admitted | any admitted out-of-extent product | Audit producer pipeline; tighten ENFORCE_EXTENT |
| Policy denial rate | < 1% of authorised consumers | > 5% sustained 10 min | Reconcile consumer RBAC against domain_role |
| Catalog sync drift | 0 (GitOps reconciled) | OutOfSync > 15 min | Re-sync ArgoCD app; validate manifest checksum |
| Product freshness | <= refresh_frequency_hours |
overdue by 25% | Trigger refresh job; alert domain steward |
Governance & Compliance Notes
Scoping rules are governance expressed as code, so every gate decision must leave an audit trail. Write each admission and denial — manifest hash, evaluated CRS, extent, resolution, and the policy decision — to an immutable ledger, so a compliance reviewer can reconstruct why any product version was published or rejected. The OPA decision log and the GitOps commit history together form that record without a separate bespoke system.
Lifecycle transitions inherit the same discipline. Marking a product deprecated should be idempotent: it routes legacy consumers to a migration endpoint while preserving historical query access for a defined retention window, and it never silently deletes a version that lineage still references. The state machine that governs those transitions — experimental, production, deprecated, archived — is detailed in Spatial Product Lifecycle Management; scoping rules are simply the admission gate that each new version must clear before it can advance through it.
Jurisdictional constraints attach to the classification and resolution fields. Sub-metre imagery and personally locatable vector data frequently carry residency or export restrictions, so the resolution gate doubles as a compliance control: a restricted product cannot be admitted at a resolution finer than policy allows, regardless of consumer role, and cross-border access is denied at the same OPA layer that enforces extent. Keeping these constraints in the same policy-as-code path as routing means a regulatory change is a versioned policy commit, not a manual audit.
Related
- Up to the parent reference: Geospatial Data Mesh Fundamentals
- Spatial Domain Boundary Design — who owns each geometry, the prerequisite to scoping it
- Product Thinking for GIS Datasets — the SLA and contract fields a scoping rule binds
- Metadata Cataloging for Raster/Vector — the index that admitted manifests are written into
- Spatial Product Lifecycle Management — the state machine scoping feeds into
- Defining scoping rules for enterprise spatial products — the field-by-field implementation detail