> ## 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.

# Events Timeline schema

> Full field reference for the Events Timeline — 1.7M+ unified events spanning permits, council decisions, AIS anomalies, OSHA violations, and more.

The Events Timeline is the unified event stream that connects every Axiom product. It contains \~1.7M events from 16+ source normalizers covering permits, council votes, AIS dark events, port calls, regulatory filings, POI lifecycle changes, crop health alerts, and more. Every other Codex dataset references an `event_id` from this timeline, making it the **graph spine** across the catalog.

Records are ingested continuously and published as monthly immutable snapshots. Every record inherits the full [APRS envelope](/codex/normalization-standard) and carries the [join keys](/codex/join-keys) documented below.

## Dataset-specific fields

| Field                | Type          | Nullable | Description                                                                                         |
| -------------------- | ------------- | :------: | --------------------------------------------------------------------------------------------------- |
| `event_type`         | dotted string |    no    | Hierarchical event type. See [event taxonomy](#event-taxonomy).                                     |
| `event_category`     | enum          |    no    | High-level grouping: `maritime`, `civic`, `regulatory`, `poi`, `environmental`, `economic`, `risk`. |
| `entity_id`          | string        |    no    | Canonical key for the affected entity. Shape depends on `entity_type`.                              |
| `entity_type`        | enum          |    no    | Type of the affected entity. See [entity types](#entity-types).                                     |
| `entity_name`        | string        |    yes   | Human-readable name (display only).                                                                 |
| `location`           | PostGIS Point |    yes   | WGS84 geometry. Use `h3_index` for joins.                                                           |
| `location_name`      | string        |    yes   | Human-readable location description.                                                                |
| `h3_index`           | string        |    yes   | H3 resolution-8 cell derived from `location`.                                                       |
| `started_at`         | timestamptz   |    no    | When the real-world event began.                                                                    |
| `resolved_at`        | timestamptz   |    yes   | When the event closed. Null if still open or point-in-time.                                         |
| `magnitude`          | float         |    yes   | Event-specific magnitude. Unit varies by `event_type`. See [magnitude units](#magnitude-units).     |
| `confidence`         | float \[0,1]  |    yes   | Pipeline confidence that the event is real.                                                         |
| `source`             | string        |    no    | Originating pipeline (`aisstream`, `socrata`, `granicus`, etc.).                                    |
| `source_ref`         | string        |    yes   | Source-native reference for re-fetch.                                                               |
| `product`            | enum          |    no    | Generating product: `locus`, `overwatch`, or `codex`.                                               |
| `downstream_outcome` | string        |    yes   | Post-hoc outcome annotation from cascade detectors.                                                 |
| `outcome_lag_days`   | integer       |    yes   | Days between this event and its downstream outcome.                                                 |
| `metadata`           | JSONB         |    yes   | Event-specific overflow fields. See [metadata keys](#metadata-keys).                                |
| `jurisdiction_slug`  | string        |    yes   | Populated for civic and regulatory events.                                                          |

## Event taxonomy

Event types use a `{domain}.{verb}` convention. You can filter at the family level (`event_type LIKE 'port.%'`) or by specific action.

### Maritime events

| Type                     | Description                                                       |
| ------------------------ | ----------------------------------------------------------------- |
| `port.entered`           | Vessel crossed port polygon inbound                               |
| `port.anchored`          | Vessel reported anchored status inside port                       |
| `port.berthed`           | Vessel matched to a specific berth                                |
| `port.departed`          | Vessel crossed port polygon outbound                              |
| `visit.in_progress`      | Open vessel visit, no departure yet                               |
| `visit.completed`        | Paired entry and departure. `magnitude` = visit duration in hours |
| `dark_event`             | AIS gap plus kinematic violation                                  |
| `satellite.{alert_type}` | Per-alert-type subtype (e.g., `vessel_cluster`, `dark_emission`)  |

### Civic events

| Type                | Description                        |
| ------------------- | ---------------------------------- |
| `council.approved`  | Council vote in favor              |
| `council.denied`    | Council vote against               |
| `council.tabled`    | Motion tabled or deferred          |
| `council.mentioned` | Topic mentioned, no decision       |
| `permit.filed`      | New permit application             |
| `permit.approved`   | Permit approved                    |
| `permit.denied`     | Permit denied                      |
| `permit.expired`    | Permit aged out without completion |
| `permit.completed`  | Work finaled                       |
| `permit.cancelled`  | Withdrawn by applicant             |
| `permit.revoked`    | Revoked by authority               |
| `noise_complaint`   | 311 noise complaint                |
| `business_license`  | New license issued                 |

### Regulatory events

| Type                     | Description                         |
| ------------------------ | ----------------------------------- |
| `regulatory.filing`      | SEC 8-K, 10-K, etc.                 |
| `regulatory.enforcement` | FDA, EPA, or OSHA action            |
| `regulatory.complaint`   | Consumer or worker complaint filing |
| `regulatory.notice`      | Authority notice                    |
| `regulatory.rule`        | Final rule publication              |

### POI events

| Type                     | Description                    |
| ------------------------ | ------------------------------ |
| `poi.opened`             | First observation of a new POI |
| `poi.active`             | Ongoing POI observation        |
| `poi.temporarily_closed` | Temporary closure              |
| `poi.closed`             | Permanently closed             |

### Environmental events

| Type                     | Description                                           |
| ------------------------ | ----------------------------------------------------- |
| `environmental.disaster` | FEMA/NWS disaster declaration                         |
| `crop.ndvi_drop`         | Sentinel-2 NDVI decline. `magnitude` = percent change |
| `crop.ndvi_recovery`     | NDVI recovery                                         |
| `river.{status}`         | Gauge status subtype (`flood`, `action`, `normal`)    |

### Economic events

| Type                | Description                                                                |
| ------------------- | -------------------------------------------------------------------------- |
| `jobs.snapshot`     | Periodic snapshot of active postings per cell. `magnitude` = listing count |
| `migration.inflow`  | Net positive migration. `magnitude` = net persons                          |
| `migration.outflow` | Net negative migration                                                     |
| `trade.{flow_type}` | Customs/CBP trade flow subtype                                             |

### Risk events

| Type            | Description      |
| --------------- | ---------------- |
| `risk.critical` | Risk score >= 85 |
| `risk.elevated` | Risk score >= 60 |
| `risk.moderate` | Risk score >= 30 |
| `risk.low`      | Risk score \< 30 |

## Entity types

The shape of `entity_id` depends on `entity_type`:

| Entity type      | `entity_id` shape                     | Example                            |
| ---------------- | ------------------------------------- | ---------------------------------- |
| `vessel`         | IMO number (preferred) or MMSI        | `9432871`                          |
| `parcel`         | `{jurisdiction_slug}:{parcel-number}` | `philadelphia-pa:12-345-678`       |
| `permit`         | `permit:{jurisdiction}:{permit-id}`   | `permit:sf-ca:2024-0412`           |
| `council_matter` | `legistar:{jurisdiction}:{matter-id}` | `legistar:phila-pa:24-0031`        |
| `poi`            | `urn:aprs:record:poi:{source}:{id}`   | `urn:aprs:record:poi:fsq:abc123`   |
| `organization`   | `urn:aprs:entity:company:{id}`        | `urn:aprs:entity:company:acme-llc` |
| `person`         | `urn:aprs:entity:person:{id}`         | `urn:aprs:entity:person:j-doe`     |
| `h3_cell`        | H3 resolution-8 string                | `88283082b9fffff`                  |
| `jurisdiction`   | `jurisdiction_slug`                   | `philadelphia-pa`                  |

## Magnitude units

`magnitude` is polymorphic — its unit depends on `event_type`. Always check `event_type` before comparing magnitude values.

| Event type pattern                          | Unit                               |
| ------------------------------------------- | ---------------------------------- |
| `visit.completed`                           | Hours (visit duration)             |
| `dark_event`                                | Hours (AIS gap)                    |
| `crop.ndvi_*`                               | Percent change vs. 5-year baseline |
| `jobs.snapshot`                             | Count of active postings           |
| `migration.*`                               | Net persons                        |
| `trade.*`                                   | USD value (notional)               |
| `risk.*`                                    | Risk score 0–100                   |
| `permit.*` (with `metadata.declared_value`) | USD value                          |

## Metadata keys

The `metadata` JSONB column holds type-specific fields. Keys are version-bound — a key present in one event type is not guaranteed in another.

| Key                     | Event types            | Description                                                                          |
| ----------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
| `kinematic_meta`        | `dark_event`           | Implied speed, Froude limit, OU max reach, actual distance, failed tests             |
| `psc_detention_history` | Maritime events        | Port State Control detentions linked to this event                                   |
| `declared_value`        | `permit.*`             | USD value declared on the permit                                                     |
| `voting_tally`          | `council.*`            | `{yes, no, abstain, absent}`                                                         |
| `alert_type_raw`        | `satellite.*`          | Upstream alert code                                                                  |
| `related_event_ids`     | Any                    | Array of `event_id` UUIDs this event is linked to. See [event chains](#event-chains) |
| `mmsi`                  | Maritime               | MMSI when `entity_type='vessel'`                                                     |
| `imo`                   | Maritime               | IMO number when known                                                                |
| `parcel_id`             | Civic (permits/zoning) | Parcel identifier                                                                    |

## Event chains

Events are often cascading effects of earlier events. The `metadata.related_event_ids` field links events into chains:

* **Maritime dark event chain:** `port.departed` → `dark_event` → `port.entered` (different port)
* **Permit cascade:** `council.approved` → `permit.filed` → `permit.approved` → `permit.completed`
* **Risk cascade:** `regulatory.enforcement` → `risk.critical`

### Traversal example

Find every downstream civic event following a dark event within 12 months:

```sql theme={null}
WITH RECURSIVE chain AS (
  SELECT id, event_type, started_at, metadata
  FROM codex.events_timeline
  WHERE id = 'c5a8e4f2-9b7d-4c1e-b3a5-1f2d8c0e7a93'

  UNION ALL

  SELECT e.id, e.event_type, e.started_at, e.metadata
  FROM codex.events_timeline e
  JOIN chain c
    ON c.id::text = ANY(
      ARRAY(SELECT jsonb_array_elements_text(e.metadata->'related_event_ids'))
    )
  WHERE e.started_at - c.started_at BETWEEN interval '0' AND interval '365 days'
)
SELECT * FROM chain
WHERE event_category = 'civic';
```

## Confidence semantics

The `confidence` field represents pipeline confidence that the event is real, not a downstream prediction score:

* **Maritime** — AIS signal quality × kinematic model posterior
* **Civic** — LLM extraction confidence × source reliability score
* **Regulatory** — 1.0 for primary-source filings; degraded for secondary mirrors
* **Environmental** — satellite cloud cover × model confidence

<Note>
  Events with `confidence < 0.4` are excluded from Research and Commercial tier exports by default.
</Note>

## Join keys

| Key                 |    Presence   | Notes                                                       |
| ------------------- | :-----------: | ----------------------------------------------------------- |
| `event_id` (= `id`) |     always    | Primary key — the spine across all Codex datasets           |
| `record_id`         |     always    | APRS URN: `urn:aprs:record:event:{product}:{id}`            |
| `chunk_id`          |     always    | Deterministic from `record_id`                              |
| `h3_index`          |     often     | Null for events without geometry (e.g., regulatory filings) |
| `jurisdiction_slug` |     often     | Always for civic and regulatory; sometimes for others       |
| `mmsi`              | maritime only | In `metadata.mmsi`                                          |
| `imo`               | maritime only | In `metadata.imo` (preferred over MMSI)                     |
| `parcel_id`         |   civic only  | In `metadata.parcel_id`                                     |
| `entity_urn`        |     often     | Present for person, organization, and POI entities          |

## Example queries

### Permit cascades after approved rezonings

```sql theme={null}
SELECT
  rez.id             AS rezoning_event_id,
  rez.jurisdiction_slug,
  rez.started_at     AS rezoning_date,
  permit.event_type  AS permit_stage,
  permit.started_at  AS permit_date,
  permit.started_at - rez.started_at AS lag
FROM codex.events_timeline rez
JOIN codex.events_timeline permit
  ON permit.metadata->'related_event_ids' ? rez.id::text
WHERE rez.event_type = 'council.approved'
  AND rez.started_at >= now() - interval '1 year'
  AND permit.event_type LIKE 'permit.%'
ORDER BY rez.jurisdiction_slug, rez.started_at;
```

### All dark events longer than 48 hours

```sql theme={null}
SELECT
  entity_name,
  started_at,
  resolved_at,
  magnitude AS gap_hours,
  metadata->'kinematic_meta'->>'implied_speed_kn' AS implied_speed
FROM read_parquet('events-timeline-2026-04.parquet')
WHERE event_type = 'dark_event'
  AND magnitude > 48
ORDER BY magnitude DESC;
```

## Known limitations

* `entity_id` shape is polymorphic — you must branch on `entity_type` before joining.
* `magnitude` units vary by event type. See [magnitude units](#magnitude-units) before comparing.
* `related_event_ids` coverage is uneven. Currently populated by maritime and permit normalizers; civic cascade linking is in progress.
* `downstream_outcome` is post-hoc and sparse — only populated once cascade detectors run, which can take 30–90 days.
