Data residency — jurisdiction-aware capsule placement

Status: experimental (ADR-0247, first slice). Placement enforcement over the object capsule store; the cryptographic proof layer (jurisdiction site seals) shipped earlier (v0.83.0) and composes with it.

What it does today

A JurisdictionRoutingAdapter wraps your per-region WORM backends and routes each tenant's capsules to the backend registered for that tenant's jurisdiction:

# jurisdictions.yaml
tenants:
  acme: EU
  globex: US
allow_cross_read:
  EU: [CH]        # directional: CH readers may read EU data; nothing else may
from novafabric.object_capsule_store.jurisdiction_router import (
    JurisdictionRoutingAdapter, load_jurisdiction_config,
)

tenants, policy = load_jurisdiction_config(Path("jurisdictions.yaml"))
store = JurisdictionRoutingAdapter(
    routes={"EU": eu_backend, "US": us_backend},
    tenant_jurisdictions=tenants,
    default=default_backend,
    residency_policy=policy,
)

Three rules, enforced not documented:

What stays planned

Per-capsule jurisdiction labels (capture-time --jurisdiction override of the tenant default), the nova lineage --jurisdiction filter, nova storage relocate with sealed relocation evidence, and wiring the router into make_adapter env configuration — all planned, tracked in ADR-0247.