Alan Turing Institute · Data Study Group
A structured database of maritime incident reports from two investigating bodies - the UK Marine Accident Investigation Branch (MAIB) and the US National Transportation Safety Board (NTSB) - hosted for you as a standard PostgreSQL database. This page orients you: what you have, how it was built, how the tables fit together, and - most importantly - how far to trust each field. The data dictionary is the per-column reference.
Read access to a running PostgreSQL database, the source report PDFs, and the paperwork to make sense of both. No access to CHIRP's application, pipeline or APIs; everything you need is in the four pieces below.
A standard PostgreSQL instance your IT service hosts. Connect with any Postgres client and query it read-only.
Every table and column defined, with the provenance and trust of each field. The companion page.
The entity-relationship diagram - every table and every link between them, below.
Every MAIB and NTSB report the database was built from, supplied as
zip archives through your IT service. Match a document row to its
file with documents.filename.
It is ordinary PostgreSQL - two things worth knowing before you query:
tsvector columns are generated. The
full-text search columns are computed automatically from their source
text and are read-only - query them for search, don't write them.
Each published report (a PDF, from MAIB or NTSB) is broken into sentence-level text plus the report's own stated incident particulars. MAIB reports are additionally linked to structured incident data - occurrences, vessels, affected persons - drawn from the MAIB Data Portal spreadsheets; NTSB has no equivalent spreadsheet source, so that layer is MAIB-only. An analysis pipeline then extracts findings from the text: safety issues, recommendations, named entities, and causal-factor classifications from CHIRP's SHIELD taxonomy. Every extracted finding is traceable back to the exact sentences of the source report.
documents.jurisdiction separates the two corpora:
'UK' for the 796 MAIB reports, 'US' for the
456 NTSB reports - 1,252 documents in all.
The schema documents the full system, but the database as delivered populates only part of it. Know which layers carry data before you build on them.
documents,
authors, sentences, and the
report-derived document_particulars /
document_vessels. Both corpora, split by
documents.jurisdiction.
occurrences, vessels,
affected_persons, affected_persons_ppe,
the report↔occurrence link on
documents.occurrence_id, and the vocabularies
taxonomy_terms / ppe_items. No NTSB
document carries an occurrence_id.
shield_codes /
shield_code_categories (full SHIELD taxonomy) and
narrative_entity_types. Loaded but not yet referenced.
chunks, chunk_sentences,
analysis - no chunking pass.
chunk_shield_codes - taxonomy loaded, no code applied
to any passage yet.
safety_issues, recommendations and their
junctions - no findings extraction.
narrative_entities,
narrative_entity_mentions - no NER/coreference pass.
organisations, legislation, the
identifier tables - nothing populates them at this stage.
The data flows through pipeline stages, and the tables mirror them. Provenance is preserved as a chain of links, not copied data: any finding traces to its passage, the passage to its sentences, each sentence to its document and position.
A report PDF - MAIB or NTSB - is registered as a
documents row and each page is rasterised to an image;
the report's own stated facts go to
document_particulars and
document_vessels, and
documents.jurisdiction records which corpus it belongs
to.
A vision LLM reads each page image and returns its text and
structure directly; deterministic passes then run on top (normalise
metadata, rejoin broken lines, repair lossy pages), stored as ordered
sentences. Lifecycle:
queued → extracting → extracted → verified.
MAIB Data Portal data is loaded independently:
occurrences → vessels → affected_persons, classified
via taxonomy_terms, linked to MAIB reports through
documents.occurrence_id. (MAIB only - NTSB
publishes no comparable dataset.)
Sentences are grouped into chunks and findings extracted
against them: SHIELD taggings, safety issues, recommendations,
entities. (Not populated in this database.)
Two incident-data sources are kept apart and linked, not merged: the
report PDF's own account lives in document_particulars /
document_vessels (both corpora); the MAIB Data Portal
spreadsheet's account in occurrences / vessels /
affected_persons (MAIB only); the two join through a
nullable documents.occurrence_id FK - several reports can
point at one occurrence (e.g. an interim then a final). Tree-shaped
classifications (event type, ship type, place on board, injury,
deviation) are normalised into taxonomy_terms. The full
entity-relationship diagram:
The data dictionary is authoritative for table and column definitions; the diagram is the map, the dictionary the legend.
This is the point of the dictionary. The database shows you structure; it cannot tell you which values are source fact, which a model produced, and which a human has since confirmed. Every column is labelled with one of the five below - the first two both mean "the source said so", and differ only in which source: a report PDF, or the MAIB spreadsheet.
| Source | Source-document field - from the report PDF, MAIB or NTSB (content or file metadata). |
| MAIB | MAIB Data Portal field - from the MAIB spreadsheet extract, on the tables it feeds (occurrences, vessels, affected_persons and their vocabularies). UK incidents only. |
| Pipeline | Pipeline-derived, deterministic - computed on ingest, no model involved. |
| AI-U | AI-generated, unverified - produced by an LLM or NLP model, not confirmed by a human. |
| AI-V | AI-generated, human-verified - model output an analyst has confirmed. |
| System | System metadata - surrogate keys, timestamps, status flags, generated search columns, seeded reference data. |
A slashed label - Pipeline / AI-U - marks a column whose extractor is deterministic with a model fallback.
Two rules run throughout. Row-level verification: tables
with an is_verified flag hold AI-generated content whose
status varies per row - treat is_verified = true as AI-V,
everything else AI-U. Sentence text is extracted by a
vision LLM reading each page image, with deterministic passes on top, so
it is AI-U, qualified by the parent documents.status
(verified = analyst-confirmed).
Read these before drawing conclusions from the data.
documents.jurisdiction: the corpora differ
in body, report format, date span and field coverage, so pooling them
silently mixes populations.
occurrences, vessels,
affected_persons and affected_persons_ppe
come from the MAIB Data Portal and cover UK incidents alone; no NTSB
document has an occurrence_id. Even on the MAIB side the
report↔occurrence link is partial: 58 of the 796 MAIB documents
carry one. Treat the occurrence tables as an incident dataset in their
own right, not as an enrichment of every report.
occurrences covers roughly 2018 onward -
it is not a full historical record, and an older report may have no
matching spreadsheet occurrence.
document_particulars and document_vessels
exist for every document, but fields are filled only where the report
states them, and NTSB reports state fewer. Of 456 NTSB / 796 MAIB
rows: accident_date 198 / 796,
accident_location 208 / 731, severity
71 / 305, accident_type 130 / 279,
loss_of_life 33 / 183;
document_vessels.port_of_origin and
destination are empty for NTSB (286 / 262 for MAIB),
while vessel_name is better covered for NTSB (400 / 299).
authors is not canonicalised. Its 22
rows carry PDF-metadata name variants of the two bodies
(MAIB, Marine Accident Investigation Branch,
www.maib.gov.uk; NTSB,
National Transportation Safety Board, the typo
NSTB) plus individual people named as a PDF's author. Use
documents.jurisdiction to identify the publishing body,
not authors.name.
documents.extraction_fallback = true - a degraded
result for some pages. 201 documents are flagged that way (182 MAIB,
19 NTSB).
status = 'verified' documents are
analyst-confirmed; extracted ones are not. As delivered
all 1,252 documents sit at extracted - none has been
analyst-verified. The source PDFs ship with the dataset, so anything
that matters can be checked against the original page.
document_particulars.accident_type / severity,
document_vessels.vessel_type) are free text - normalise
before counting, and note MAIB and NTSB word them differently, so the
free text is doubly heterogeneous. Identifiers differ too:
publication_number is a MAIB Publication_No
for UK reports and an NTSB report number (MAB-,
MIR-, MAR-) for US ones, and
document_type is a GOV.UK publication class that is null
for every NTSB document. Spreadsheet classifications are normalised into
taxonomy_terms and referenced by *_term_id.
Coordinates are verbatim text, not validated geo types.
As of 17 August 2026. Populated tables carry data; the analysis and findings layer is empty in the database (see above). Seeded vocabularies are loaded reference data.
| Table | Rows |
|---|---|
| documents | 1,252 (796 MAIB, 456 NTSB) |
| document_particulars | 1,252 |
| document_vessels | 1,252 |
| authors | 22 |
| occurrences | 9,063 (MAIB only) |
| vessels | 9,830 (MAIB only) |
| affected_persons | 3,040 (MAIB only) |
| affected_persons_ppe | 924 (MAIB only) |
| taxonomy_terms | 410 |
| ppe_items | 9 |
| sentences | 341,057 (293,454 MAIB, 47,603 NTSB) |
| chunks · analysis · findings · entities | 0 (empty) |
| shield_codes | 96 (seeded) |
| shield_code_categories | 20 (seeded) |
| narrative_entity_types | 5 (seeded) |