For every completed vessel visit, Axiom Overwatch decomposes the arrival-to-departure window into the time spent in each operational state. This answers the “where did the time actually go” question that a singleDocumentation Index
Fetch the complete documentation index at: https://docs.axiomancer.io/llms.txt
Use this file to discover all available pages before exploring further.
berth_hours figure cannot.
When to use this
- Quantify anchorage queues vs. berth productivity at a port
- Benchmark turnaround performance across vessels and operators
- Surface idle time inside a visit that does not map to anchor or berth
- Build congestion analytics that distinguish “waiting outside” from “alongside but slow”
The breakdown
Each closed vessel visit produces one row keyed byvisit_id:
| Field | Description |
|---|---|
total_hours | Full window from arrived_at to departed_at. |
approach_hours | Time from the entered event to the first anchored, berthed, or departed event. |
anchor_wait_hours | Sum of segments where the vessel was in the anchored state. |
berth_hours | Sum of segments where the vessel was in the berthed state. |
idle_other_hours | Residual inside the visit window not attributed above (typically pre-first-event slack). |
classification_method | event_segments when anchor or berth events are present, fallback_total when only entry/exit are known. |
computed_at | Timestamp the row was written. |
approach_hours + anchor_wait_hours + berth_hours + idle_other_hours reconciles to total_hours (within rounding).
How it’s computed
The classifier walksport_events between arrived_at and departed_at and attributes the inter-event delta to the earlier event’s state. A vessel that is anchored at 02:00 and berthed at 10:00 contributes 8 hours to anchor_wait_hours.
When a visit has neither an anchored nor a berthed event — usually old or sparse data — the entire window is booked to approach_hours and classification_method is set to fallback_total. Filter on this column when you need only fully-classified visits.
The TypeScript classifier runs on every departure close, so live visits get an allocation row as soon as the visit closes. Historical visits without a row are filled in by a SQL-side backfill (see below).
Canal transit time is currently bucketed into
approach_hours. A dedicated canal_hours column is planned once canal polygons are wired into the event stream.Querying
The data lives in thevessel_visit_time_allocation table, indexed for (port_id, departed_at DESC) and (imo_number, departed_at DESC).
Backfilling historical visits
Visits that closed before this feature shipped do not have allocation rows. Thebackfill_visit_time_allocation(p_limit) RPC processes a bounded batch of unclassified departed visits using the same segmentation logic as the live writer. It is idempotent — existing rows are not overwritten.
Field reconciliation
If you previously joinedvessel_visits.berth_hours for productivity dashboards, that column still exists and is unchanged. The allocation table is a sibling, not a replacement — vessel_visits stays narrow. Joining on visit_id gives you both views in one query: