Skip to main content
Public records are inherently temporal, and most normalization failures stem from conflating different time dimensions. This page maps every temporal field Codex emits per dataset, so you never have to guess which clock a timestamp is on.

Universal fields

Every Codex record carries up to seven temporal fields where semantically applicable. These extend the normalization standard bitemporal contract.
FieldMeaning
ingested_atWhen the Codex system first observed the row. Never mutates after insert.
modified_atWhen the row was last updated. Refreshed on every write.
occurred_atWhen the real-world event actually happened.
filed_atWhen the record was filed or submitted to the authority.
published_atWhen the source authority published the record.
effective_fromWhen the record or ruling became legally effective.
effective_toWhen it expired or was superseded. Null means currently active.
filed_at is distinct from occurred_at for records where the filing is itself the event (e.g. SEC filings) versus records where filing follows the event (e.g. a council vote happens, minutes are filed days later).

Field availability by dataset

FieldCivicEventsAISUSGLEHDPOIPermitsOSHA
ingested_atrequiredrequiredrequiredrequiredrequiredrequiredrequiredrequired
modified_atrequiredrequiredrequiredrequiredrequiredrequiredrequiredrequired
occurred_atrequiredrequiredrequiredoptionalrequiredrequired
filed_atoptionaloptionalrequiredrequired
published_atrequiredoptionaloptionaloptionaloptional
effective_fromoptionalrequired
effective_tooptionaloptional

Domain-specific temporal fields

Some datasets carry additional temporal fields beyond the universal set.

AIS Maritime — port-call lifecycle

Port calls have four clocks that must not be conflated:
FieldMeaningSource
etaEstimated time of arrivalVessel-declared (AIS message 5)
ataActual time of arrivalObserved from first in-port AIS position
etdEstimated time of departureVessel-declared or port authority schedule
atdActual time of departureObserved from last in-port AIS position
occurred_at is set to ata for port.entered events and atd for port.departed events. ETA/ETD are retained as separate fields, never overwritten by actuals. Use both to analyze punctuality:
SELECT vessel_name, port_id, (ata - eta) AS arrival_delay
FROM port_calls
WHERE ata IS NOT NULL AND eta IS NOT NULL;

Permits — six-stage lifecycle

Each permit record carries up to six stage-specific timestamps. Only filed_at is universally present; others are populated as stages complete.
FieldMeaning
filed_atApplication filed with the authority (required)
applied_atAlias for filed_at in jurisdictions that use the term
approved_atApproved by the authority
issued_atPermit issued or recorded. May differ from approved_at by days.
inspected_atLast inspection, if tracked
expired_atExpired or withdrawn
occurred_at is set to the stage-specific timestamp of the event type — a permit.filed event has occurred_at = filed_at, a permit.approved event has occurred_at = approved_at.

Civic Intelligence — publication lag

For council proceedings, the gap between occurred_at (meeting date) and published_at (minutes publication) can be days to weeks. Both fields are always populated so you can analyze either event time or public-record time.

OSHA — case lifecycle

FieldOSHA source columnMeaning
filed_atopen_dateInspection opened
occurred_atvariesEvent that triggered inspection
modified_atclose_case_dateCase closed, or last update if still open

Common pitfalls

Avoid these temporal field mistakes — they are the most common source of data errors in downstream analysis.
  • Single-timestamp fallacy. Do not collapse occurred_at, published_at, and filed_at into one field. They are rarely the same value.
  • Using ingested_at for event-time analysis. ingested_at is the wrong clock for analysis — use occurred_at or the domain-specific actual time.
  • Forgetting modified_at on updates. Every writer must refresh modified_at. Skipping this breaks incremental-sync consumers.
  • Overwriting ETA with ATA. Overwriting the estimate with the actual loses the punctuality signal. Keep both.
  • Confusing applied_at and filed_at. Some jurisdictions distinguish these. Codex publishes one or the other per record, never both with different values.

Example queries

Permits filed but not yet approved after 90 days

SELECT id, filed_at, jurisdiction_slug
FROM normalized_permits
WHERE approved_at IS NULL
  AND filed_at < now() - interval '90 days';

Publication lag distribution for council proceedings

SELECT
  jurisdiction_slug,
  percentile_cont(0.5) WITHIN GROUP (ORDER BY published_at - occurred_at) AS p50_lag,
  percentile_cont(0.9) WITHIN GROUP (ORDER BY published_at - occurred_at) AS p90_lag
FROM civic_records
WHERE published_at IS NOT NULL AND occurred_at IS NOT NULL
GROUP BY jurisdiction_slug;

Port calls where arrival was more than 12 hours late

SELECT vessel_name, port_id, ata - eta AS delay_hours
FROM port_calls
WHERE ata IS NOT NULL AND eta IS NOT NULL
  AND ata - eta > interval '12 hours';