Phase 2 — Runtime Engine Scope

Phase 1 (built) renders the 21-model v0.2 schema as an AI-Safe CRUD register: tenants, layers, features, evaluation runs, relationships, rules, events, deliveries, disclosures, transfers, audit and reconciliation — browsable, with a dashboard and a live Leaflet map. But the states are static: the seed shows relationships already detected, events already emitted and delivered, a disclosure already sent. Nothing is computed, triggered or enforced by the system.

Phase 2 is the runtime that makes it live — running the spatial engine over geometries, evaluating rules, firing triggers and events, enforcing disclosure boundaries, delivering to the Orchestrator and reconciling cross-tenant state. Same shape as the (built, live) Orchestrator event pipeline, but with a geometry engine at its core.

Everything below is drawn from the v0.2 pack's config/ (spatial_engine, triggers, orchestrator) and rules/ (spatial_rules, disclosure_profiles, event_templates). It is a scope, not a design.


A. The spatial engine

The headline. On a feature change (or a scheduled sweep), a SpatialEvaluationRun computes geometric relationships between candidate features (config/spatial_engine.yaml, engine Shapely):

  • Candidate selection by bbox/tenant/layer, then exact predicate — intersects, within, contains, touches, crosses, overlaps, near (distance) — writing/updating SpatialRelationships with overlap_area_m2 / distance_m.
  • CRS discipline: geometry is stored and exchanged in EPSG:4326, but every metric operation (distance, buffer, overlap area, simplification) is transformed into EPSG:7856 first — the demo's RP-2026-001 near PIPE-44 = 197.474 m is a projected metric distance.
  • Relationship lifecycle: detected → active → changed → ceased/resolved, using the timestamps the model already carries (first_detected_at, last_confirmed_at, changed_at, ceased_at). The seed's RP-2026-002 → ML-1032 (ceased) is exactly this path.
  • The run records candidate_count / match_count / metrics — the demo's EVAL-2026-0101 (8 candidates, 4 matches).

Decisions: near-distance threshold defaults, geometry validation/repair policy, incremental vs full re-evaluation, coordinate precision/equality tolerance.

B. Rules → triggers → events

SpatialRule matches a layer-pair + relationship type at a severity; a matched relationship, against a TriggerDefinition (watched events + actions), raises a SpatialEvent rendered from an event template (rules/event_templates.yaml):

  • The demo: road_projects intersects environmental_areas (critical) → gis.environment.review_required; road_projects near pipelines (warning) → gis.utility.proximity_detected.
  • Event lifecycle pending → emitted → acknowledged → closed; EventDelivery posts to each destination with idempotency (idempotency_key = event_id, header X-Event-ID) and retry (attempt_count, backoff 5/15/60/300/900 s).

Decisions: rule evaluation order/precedence; event de-duplication window; delivery backoff and dead-lettering.

C. Tenancy & disclosure enforcement

The security core. Every read/share/disclosure is bounded by tenancy:

  • LayerShare sets the access level (metadata / geometry / read / export) another tenant has to a layer — the engine must never expose more than the share grants.
  • A DisclosureProfile (geometry policy none/centroid/simplified/full + field allow/deny lists) governs what a cross-tenant disclosure actually contains. The demo's coordination_basic shares geometry + coordination properties but denies internal_target_model, commercial_notes, resource_estimate — so mining's CONFIDENTIAL-DEMO target model never crosses to transport. A disclosure that would exceed the profile is blocked or down-resolved (e.g. full geometry → centroid).
  • Permission scopes (tenant/layer/feature) gate user actions; the pack's tests/access_matrix.yaml is the ready-made who-can-see-what test.

Decisions: how geometry is simplified/generalised for simplified/centroid policies; push vs pull disclosure; consent capture.

D. Data transfer & audit

A disclosure or export becomes a DataTransfer (direction, format, record count, checksum, payload ref) delivered to the destination; every material action writes an AuditEvent (with before/after state and context). This is the defensible record of what was shared with whom — the demo's outbound GeoJSON transfer to the Orchestrator and its disclosure.sent audit row.

E. Reconciliation

ReconciliationCheck verifies that shared/disclosed state stays consistent across tenants — e.g. a coordination relationship is present and equivalent on both sides after delivery — flagging an exception_code when it drifts. The seed's RECON-2026-0012 (STALE_RELATIONSHIP) is exactly this: local state says the RP-2026-002 intersection ceased, but the Orchestrator still lists it active, awaiting resync.

F. Orchestrator integration

config/orchestrator.yaml maps spatial events to the DSLCore Orchestrator (POST http://orchestrator:8000/api/v1/events, envelope source_system: gis_tenancy_portal): a road-project/mining-lease intersection here can drive a downstream coordination workflow in another app. Delivery is the same outbox pattern as the rest of the suite, with a health probe at /api/v1/integrations/orchestrator/health.


How it would be built

  1. A spatial engine service (A) with a real geometry library and CRS transforms — the app's defining capability.
  2. The rule/trigger/event pipeline (B) on top of it, reusing the Orchestrator event contracts.
  3. Tenancy + disclosure enforcement (C) — the non-negotiable isolation guarantees, tested adversarially against tests/access_matrix.yaml.
  4. Transfer/audit + reconciliation (D, E) and Orchestrator wiring (F).
  5. Tests from the pack's tests/scenarios.yaml (SCN-001…008, positive/negative/boundary/cessation) and expected_relationships.yaml / expected_events.yaml — ready-made and deterministic.

Suggested sequencing

  1. Spatial engine (A) — makes relationships real; everything else depends on it.
  2. Rules → events (B) — turns geometry into actionable coordination signals.
  3. Tenancy & disclosure enforcement (C) — the security core; gate before you share.
  4. Transfer/audit + reconciliation (D, E) — the defensible cross-tenant record.
  5. Orchestrator integration (F) — drive downstream workflows.

Each slice is independently shippable and demoable. The Orchestrator (built and run live) is the working template for the event pipeline, delivery and tests.