# Ontology — shared across all scenarios

> Synthetic demo data inspired by real Baltic geography, MMSI/OUI conventions, and infrastructure. Not real observations.

This ontology backs cross-source fusion, Power BI semantic models, KQL graph queries, and Fabric Data Agents.

## Node types

| Node | Key | Attributes |
|---|---|---|
| Vessel | mmsi | imo, name, type, flag, loa_m, beam_m, draft_m, callsign |
| Person | personId | ship, role |
| Device | macAddress | ouiVendor, persistent_for_personId? |
| Sensor | sensorId | kind (mac/radar), subtype (coastal/port/airborne/plane/drone), location_geom |
| Infrastructure | featureId | kind (cable/pipeline/junction/port/site/lane/eez), geom |
| Track | trackId | sourceSensorId, start_ts, end_ts |
| Observation | obsId | sensorId, ts, geom, signal_strength? |
| Event | eventId | scenarioId, stage?, kind, ts, confidence |

## Edge types

| Edge | From | To | Attributes |
|---|---|---|---|
| owns_device | Person | Device | since_ts? |
| assigned_to | Person | Vessel | role |
| observed_at | Device | Sensor | ts, signal_strength_dbm, session_id |
| radar_detects | Sensor | Track | start_ts, end_ts |
| track_position | Track | Observation | ts, lat, lon, alt_m? |
| vessel_position | Vessel | Observation | ts (from AIS) |
| near_to | Vessel/Track | Infrastructure | distance_m, ts |
| met_with | Vessel | Vessel | start_ts, end_ts, min_distance_m |
| deviated_from | Track | PlannedRoute | offset_nm, ts |
| launched_from | Track | Vessel | takeoff_ts, recovery_ts? |
| spoofs | Vessel | Vessel | scenarioId="S4", evidence_summary |
| co_observed | Device | Device | sensorId, overlap_ts_start, overlap_ts_end |
| part_of | Event | Scenario | role |

## Example triples (S6 flagship)

```
(MV AALLOTAR)              -[vessel_position]-> (obs_05:30:00)
(P-AAL-OP1.iPad)           -[owns_device@P-AAL-OP1]
(P-AAL-OP1.iPad)           -[observed_at@MAC-HKO-COAST-01, ts=05:18:14Z, rssi=-82]
(drone_5C:E2:8C:DD:EE:01)  -[observed_at@MAC-AIR-DRN-01, ts=13:45:11Z, rssi=-58]
(P-AAL-OP1.iPad)           -[co_observed@MAC-AIR-DRN-01]-> (drone_5C:E2:8C:DD:EE:01)
(track_DR-7741)            -[launched_from]-> (MV AALLOTAR)
(MV AALLOTAR)              -[met_with, min=58m, dur=22min]-> (MV SUMUKKO)
(MV AALLOTAR)              -[near_to, d=120m]-> (BalticConnector)
(MV AALLOTAR)              -[deviated_from, offset=6.0nm]-> (planned_route_aal_2025-10-15)
```

## Confidence-scoring framework

All evidence signals are normalized to [0,1]; the composite incident score is a weighted sum.

```
incident_score = Σ ( w_i * signal_i ),  Σ w_i = 1
```

Signal library (15):

| signal | computed from | normalization |
|---|---|---|
| `ais_gap_score` | gap_duration_s, vessel_type | `sigmoid((gap_s - 300) / 600)` |
| `ais_radar_delta_score` | max positional delta over window (m) | `clamp(delta_m / 1000, 0, 1)` |
| `ais_type_behavior_mismatch_score` | declared_type vs observed behavior class | binary 0/1 |
| `mac_attribution_score` | observation_count_at_correct_geometry / total | direct ratio |
| `mac_fingerprint_anomaly_score` | 1 − Jaccard(today_macs, baseline_macs) | direct |
| `mac_first_seen_ratio` | new_macs / total_macs in window at sensor | direct |
| `mac_count_zscore` | (count − μ) / σ vs 90-day baseline | `sigmoid((z − 3) / 2)` |
| `mac_manufacturer_jsd_score` | Jensen–Shannon divergence vs baseline mix | direct (0..1) |
| `spatial_proximity_infra_score` | min(distance_m, threshold) inverse | `1 − d / threshold` |
| `temporal_dwell_score` | continuous_time_in_polygon_minutes | `sigmoid((min − 30) / 30)` |
| `vessel_pair_proximity_score` | min separation (m) and duration | `min(1, dur_s / 600) × (1 − d / 200)` |
| `track_origin_offshore_anomaly_score` | offshore_km × (1 − has_flight_plan) | binary × continuous |
| `co_observation_score` | airborne sensor sees ≥2 linked MACs with RSSI > -65 dBm | binary 0/1 |
| `duplicate_mmsi_score` | two AIS broadcasts same MMSI > N km apart in T s | binary 0/1 |
| `dimension_speed_plausibility_score` | physical dimensions vs sustained speed/RCS truth | continuous |

Per-scenario default weights live in `scenarios/<id>/weights.json`. Alert threshold is also per scenario.
