Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.axiomancer.io/llms.txt

Use this file to discover all available pages before exploring further.

Axiom Overwatch tracks vessel transits through four hand-curated maritime chokepoints — Bab-el-Mandeb, the Strait of Hormuz, the southern Suez approaches, and Cape Agulhas — by fusing live AIS dead-reckoning with cued Sentinel-1 SAR scenes. The pipeline predicts when each vessel will enter a corridor, schedules a radar look at the predicted window, and reconciles the AIS narrative with the SAR observation to flag confirmed transits, dark transits (SAR pixel with no AIS), and missed transits. This is the free-tier alternative to commercial S-AIS chokepoint coverage. It runs on Copernicus open data and powers the chokepoint widgets on the Overwatch cockpit.

When to use this

  • Monitor sanctions-relevant routing (Houthi-rerouting around Bab-el-Mandeb, Cape detour vs. Suez, Hormuz dark-fleet activity).
  • Detect vessels that disappeared from AIS but were observed transiting a corridor by SAR.
  • Backtest predicted ETA accuracy at a chokepoint over a custom window.
  • Power a cockpit widget that lists confirmed / dark / missed transits per corridor for a recent period.
If you only need vessel-level routing without corridor semantics, use Route forecasts. If you only need a coverage check for a single SAR scene, use the SAR coverage API.

The chokepoints

Four corridor polygons ship as seed data in public.chokepoints. Each row carries a corridor geom plus an entry_zone and exit_zone used by the predictor and reconciler.
idNameNotes
bab-el-mandebBab-el-Mandeb / Red Sea SouthStrait between Yemen and Djibouti. Entry from the Gulf of Aden (south), exit into the Red Sea (north).
hormuzStrait of Hormuz / N GulfIran / UAE / Oman strait. Entry from the Persian Gulf (west), exit into the Gulf of Oman (east). Reverse direction also valid.
suez-sSuez S approaches / Red Sea NorthSouthern Suez approach. The canal interior is land-locked — surface analytics are limited to the southern entry.
cape-agulhasCape Agulhas / Southern AfricaAtlantic ↔ Indian Ocean rounding point. Sanctions-era detour analytics.
All four corridor polygons, plus their entry and exit zones, are GIST-indexed and available via SELECT * FROM public.chokepoints.

The transit lifecycle

Every predicted or observed transit is one row in public.vessel_transits. The row moves through a strict status lifecycle:
predicted ──► confirmed         (AIS reappearance in exit_zone, or SAR pixel match, or both)
          ──► dark_transit      (SAR pixel match with no prior AIS prediction)
          ──► missed            (96h post-ETA elapsed with no reappearance)
          ──► cancelled         (vessel re-routed away from the corridor before ETA)
A semantic invariant is enforced at the database level:
  • dark_transit rows must have a sar_scene_id and pixel_match_lat/pixel_match_lon, and no predicted_imo (the vessel was not predicted by AIS).
  • All other statuses (predicted, confirmed, missed, cancelled) must have a predicted_imo and predicted_eta.
confirmed_via records how the confirmation happened: ais_reappear, sar_pixel, or combined.

vessel_transits

FieldDescription
idUUID, primary key.
predicted_imoVessel IMO from the AIS prediction. NULL for dark_transit.
chokepoint_idFK to chokepoints(id).
predicted_etaProjected entry time at the corridor. NULL for dark_transit.
eta_uncertainty_hoursOne-sigma band around predicted_eta. Floor of 1 hour.
predicted_atWhen the prediction row was inserted.
last_known_lat / last_known_lon / last_known_speed / last_known_courseAIS snapshot the prediction was projected from, retained for forensic reconstruction.
sar_scene_idCopernicus product identifier of the cued SAR scene. Filled by the matcher.
sar_scene_acquired_atSAR acquisition timestamp.
pixel_match_lat / pixel_match_lonCFAR pixel coordinates that satisfied the match.
pixel_detection_countNumber of CFAR detections in the matching cluster.
match_confidence0 to 1 confidence score for the AIS↔SAR match.
statuspredicted / confirmed / dark_transit / missed / cancelled.
confirmed_atTimestamp the row was promoted out of predicted.
confirmed_viaais_reappear / sar_pixel / combined.

How it’s computed

Five jobs make up the AIS-SAR fusion pipeline. Each one is an independently scheduled cron with its own ingestion-log trail.
CronScheduleRole
populate-predicted-transits-hourly5 * * * *Tip — call predict_chokepoint_eta for every active vessel and upsert predictions.
monitor-corridor-sar15 */6 * * *Cue — pull Sentinel-1 scenes that intersect upcoming predicted windows.
reconcile-vessel-transits20,50 * * * *Match — promote predicted rows to confirmed / missed, attach SAR scenes.
verify-dark-fleet-sar-daily0 8 * * *Daily SAR sweep over high/critical dark events (SAR detections).
refresh-mv-chokepoint-transits-weekly30 3 * * *Refresh the weekly reporting matview.

The predictor: predict_chokepoint_eta

predict_chokepoint_eta(p_imo TEXT, p_lookback_hours INTEGER DEFAULT 6) is a STABLE Postgres function that does straight-line dead-reckoning from a vessel’s latest live AIS position toward each chokepoint polygon. A vessel is eligible for prediction only when its latest position satisfies all of:
  • timestamp is within p_lookback_hours of now()
  • speed >= 1.0 knots (drifting / stationary vessels are rejected)
  • course IS NOT NULL and between 0 and 360 degrees
  • latitude and longitude are present
The function projects the vessel hourly for 72 hours along its current course at its current speed (using ST_Project on a geography type), builds a track line, and returns one row per chokepoint the track intersects. The ETA is interpolated from the track-line fraction of the first hit; uncertainty is 15% of hours-ahead with a 1-hour floor. If the vessel is dark, drifting, or has no heading, the function returns no rows — the predictor silently skips it.
-- All chokepoints the vessel is projected to enter in the next 72h.
select chokepoint_id, predicted_eta, eta_uncertainty_hours
from predict_chokepoint_eta('9876543', 6);

The cuer: monitor-corridor-sar

Every 6 hours the monitor-corridor-sar Edge Function reads pending predicted rows whose predicted_eta falls inside the next scan window, queries the Copernicus Data Space Sentinel-1 catalog for IW_GRDH_1S scenes intersecting each chokepoint corridor, and writes back any matched sar_scene_id / sar_scene_acquired_at onto the prediction row. CFAR pixel detection on the matched scene populates pixel_detection_count, pixel_match_lat, pixel_match_lon, and match_confidence. This source is registered in data_source_catalog as monitor-corridor-sar and shows on the data-source dashboard alongside aishub and fred.

The matcher / reconciler

Twice per hour, reconcile-vessel-transits walks the predicted rows:
  • A vessel reappearing inside the corridor’s exit_zone after its predicted_eta is promoted to confirmed (confirmed_via = 'ais_reappear').
  • A SAR pixel match within the corridor and inside the ETA uncertainty band is promoted to confirmed (confirmed_via = 'sar_pixel', or combined if both signals agree).
  • A row whose predicted_eta + 96h has elapsed with no reappearance and no SAR match is promoted to missed.
  • A vessel that exits the predicted approach without entering the corridor is cancelled.
A separate path inserts dark_transit rows directly when monitor-corridor-sar finds a CFAR cluster inside a corridor that doesn’t match any predicted row.

Reading transits

Two access paths are exposed and both are usable from PostgREST or SQL.

get_chokepoint_transits RPC

Cockpit-friendly RPC for a single chokepoint over a time window. Defaults to the last 14 days. SECURITY DEFINER, granted to authenticated, anon, and service_role.
select id, predicted_imo, predicted_eta, status,
       match_confidence, pixel_detection_count,
       sar_scene_id, sar_scene_acquired_at,
       confirmed_at, confirmed_via
from get_chokepoint_transits('bab-el-mandeb', now() - interval '7 days');
curl -X POST 'https://<project>.supabase.co/rest/v1/rpc/get_chokepoint_transits' \
  -H "apikey: $ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"p_chokepoint_id":"hormuz","p_since":"2026-04-01T00:00:00Z"}'

mv_chokepoint_transits_weekly matview

Weekly aggregates per chokepoint per status, with median ETA accuracy. Refreshed nightly at 03:30 UTC (refresh-mv-chokepoint-transits-weekly). Use this for trend dashboards instead of scanning vessel_transits directly.
ColumnDescription
chokepoint_idCorridor key.
week_startMonday-anchored week start.
statuspredicted / confirmed / dark_transit / missed / cancelled.
nRow count for that bucket.
median_eta_delta_hoursMedian (confirmed_atpredicted_eta) in hours, only over confirmed rows.
sample_idsUp to N most-recent transit IDs in that bucket, for drilldown.
-- Confirmation rate per corridor for the last 8 weeks.
select chokepoint_id, week_start,
       sum(n) filter (where status = 'confirmed')::float
         / nullif(sum(n) filter (where status in ('confirmed','missed')), 0) as confirm_rate,
       sum(n) filter (where status = 'dark_transit') as dark_count
from mv_chokepoint_transits_weekly
where week_start >= now() - interval '56 days'
group by chokepoint_id, week_start
order by week_start desc, chokepoint_id;

SAR detections storage

verify-dark-fleet-sar-daily runs every morning at 08:00 UTC over recent high/critical dark_events. When the Copernicus catalog returns a Sentinel-1 scene over the dark-event location and the CFAR detector returns at least one ship pixel, one row lands in public.sar_detections, FK’d back to the originating dark_event.
FieldDescription
dark_event_idFK to dark_events. Cascades on delete.
vessel_imoIMO of the dark-event vessel.
scene_id / scene_acquired_atCopernicus product id and acquisition time.
detection_lat / detection_lonPixel-level CFAR detection coordinates.
distance_to_expected_nmDistance from the AIS-expected position to the SAR pixel.
cfar_score / mean_confidence / max_confidenceCFAR scoring outputs.
ship_size_estimatePixel-derived size estimate.
pixel_detection_countNumber of pixels in the matched cluster.
detection_methodVersioned method tag. Currently sentinel-1-cfar-v1.
This source is registered in data_source_catalog as verify-dark-fleet-sar.
Following the risk_tier recalibration and the Yager fusion fix, the daily 08:00 UTC sweep now writes detections to sar_detections over the live high+critical queue. Events with no SAR observation (low/medium coverage potential, missing Copernicus credentials, or a detectShips failure) keep their pre-fusion AIS risk_score rather than being pulled toward Lawful.

Operational notes

  • All five crons write one row per run to ingestion_logs. Filter by source = 'monitor_corridor_sar', populate_predicted_transits, reconcile_vessel_transits, verify_dark_fleet_sar, or refresh_mv_chokepoint_transits_weekly to inspect run history.
  • The unique partial index vessel_transits_predicted_uniq (predicted_imo, chokepoint_id, predicted_eta) makes the predictor idempotent within a single ETA bucket. Re-running the hourly cron is safe.
  • The unique partial index vessel_transits_dark_uniq (sar_scene_id, pixel_match_lat, pixel_match_lon) WHERE status = 'dark_transit' deduplicates dark-transit inserts across SAR scene re-ingestion.
  • chokepoints and vessel_transits are RLS-protected with read-all policies; writes are service-role only.
  • Both new SAR sources use the free Copernicus tier — no credentials required for catalog metadata, with COPERNICUS_CLIENT_ID / COPERNICUS_CLIENT_SECRET enabling pixel-level CFAR.