PrompTugal.newsStorm CharlesUpdated 12:12 UTCNew here?v0.1.1049Repo
Not a warning service. Follow IPMA, ANEPC and your local authorities. We aggregate public sources, each with its source and the time we read it.

The graph of the storm, and its ontology

Kept by incident.graph@web-summit.dinis, 11 November 2026, 07:57 UTC

One graph of Storm Charles: who decided and warned what, when, what was reported, where it was read, and which agent keeps which dataset. Kept by incident.graph@web-summit.dinis. Built from the incident's JSON files by tools/graph-build.mjs, never by hand. Not a warning service: the graph records what the authorities decided and warned and when we read it; follow IPMA and ANEPC.

Files

FileWhat
ontology.jsonthe eight kinds of thing and nine verbs below, each with its inverse; the builder refuses anything else
storm.jsonthe graph: nodes[] and edges[] (one per line), counts, built_from (each input file with its sha256). the actors, the warnings for Lisbon, places and agents; more names the parts below, which a reader joins into one graph
storm-decisions.jsonpart of the graph, same shape: every Decision, with the decides, precedes and affects edges that touch it; its edges point into storm.json (its own part since 11 November, 07:58 UTC)
storm-signals.jsonpart of the graph, same shape: every Signal (a row of the timeline) with the edges that touch it
storm-sources.jsonpart of the graph, same shape: every Source and Dataset, with the cites and produced-by edges that touch them; its edges point into storm.json
storm-elsewhere.jsonthe rest of the graph, same shape: the warnings in force in the other districts, and those districts; its edges point into storm.json
tables/timeline.jsonthe lead-time line: every warning and decision with a time known to the minute, in order, with the hours between them and before the red warnings start
tables/decisions.jsondecisions and issued warnings: by whom, what, when, status, what each followed
tables/warnings.jsonwarnings: issued, in force (type, level, area, start, end), and the history of when each was first seen
tables/signals.jsonthe timeline, one row per signal, with its publisher
tables/sources.jsonevery URL read, its publisher, how often it is cited
tables/first_on_fact.jsonwho was first on each keyed fact, per outlet, with the minutes after the primary source (from the media watch; analysis, labelled hypothesis)
tables/coverage.jsonwhat each outlet published on the storm and when (from the media watch; no by-line names)
tables/actors.jsonbodies, operators, the organiser, outlets
ref/ipma-areas.jsonIPMA's warning areas by code (names and coordinates), from IPMA's own list
queries.jsonthe worked SQL queries of the query page

The ontology on one page

Every node and every edge carries four things: label (fact, evidence or hypothesis), source (an https URL), read (the UTC time it was read) and origin (the file and place it was built from).

Kind of thingWhat it isBuilt from
Actorsomeone who decides, warns or reports; kind is body (an authority, the government, a municipality), operator (transport, a venue, schools), organiser (Web Summit) or outlet (press and public social platforms)decisions/graph.json nodes; outlets from the hosts of cited URLs
Decisionsomething an actor decided, or has not yet announced (status)decisions/graph.json edges
Warninga warning from a body that warns: issued, in_force, or cap (IPMA's own message, with the time IPMA sent it)IPMA's and ANEPC's edges; weather/warnings.json; weather/cap.json
Signala row of the timeline: something published, said or observedsignals.json
Sourcea URL that was readdecisions/sources.json; any other cited URL; the pages covering the storm (research/weather-sites/sites.json)
Placewhere a warning applies: an IPMA area, mainland Portugalweather/warnings.json; ref/ipma-areas.json
Dataseta JSON file of the incidentthe files under the incident's data/
Agentan agent or desk that reads sources and keeps datasetsdata/keys.json; read_by in the datasets
VerbIts inverseFrom, toMeaning
decidesdecided-byActor, Decisionthe actor made (or owes) this decision
warnswarned-byActor, Warningthe body issued this warning
reportsreported-byActor, Signal or Decision or Warningthe actor published it
citescited-byDecision or Warning or Signal, Sourcethe item was read at this URL (or is corroborated by it)
precedesfollowsDecision or Warning, Decision or Warningtime order between two linked items, with lead_minutes when both times are known to the minute. Order, not cause
affectsaffected-byDecision or Warning, Actorthe actors a decision touches (the researcher's to)
located-incontainsWarning or Place, Placea warning's area
produced-byproducesDataset or Source, Agent or Actorwho made it
issued-asissue-ofWarning, Warningthe same warning, opened: a warning as recorded (or in force) and the body's own message that carries it (IPMA's CAP message, with the time sent)

Labels. A fact was read on the channel of the body that decides or warns. Evidence is reported by others, with its source. A hypothesis is our analysis, with its reasons, never stated as fact. A derived item takes the label of the item it came from; an outlet, a place, a dataset or an agent is a fact about the file or URL that names it.

Not in the graph: people. No private person is a node; journalists and officials are not modelled here. Forecast values and observations stay in weather/*.json: the graph links the dataset, not each number.

Two hand-kept lists, both in the ontology: own_channels (seven hosts that are plainly an actor's own, two that are never outlets) and public_posts (below). Everything else is derived.

No private person is named or linked. A personal post address on a social platform never enters the graph or a table: the builder keeps the host only, and stops with nothing written if one would reach an output. The exceptions are the researcher's listed official channels and the rows named in public_posts, each with its reason and who decided (today one: a public figure in a public role).

Where it joins the other graphs (crossings.json)

The site has other graphs: the register of sources (sources/), the weather data supply chain (meteorology/), the entities (entities/) and our dated captures (evidence/, Wayback). This graph joins them and copies none of them: each keeps its own kinds, verbs and ids, and none of their nodes is a node here. crossings.json is built with the graph and holds:

  • edges: each from a node of this graph to <world>/<that world's own id>, with rel (a verb with an inverse, from ontology.json, crossings), href (that world's own page), label, source, read, origin and why. registered-as (an actor's entry in the register of sources), in-lineage-as (the same thing in the supply chain), has-site (a weather site the actor publishes), publishes-as (its dataset or warning service there), issued-through (a warning to the warning service it came through, and from there down to the models and instruments).
  • captures: once per address this graph was read at, our latest capture of it (evidence/<id>.html) or the reason there is none. The pages put it before every outside link: an item, its source, our capture, the outside address.
  • ids_to_settle: ids that mean one thing here and another in a neighbour's file.

The entity id is the pivot (one id per thing): a crossing is a fact where the other world itself names the entity that names this graph's node, and a hypothesis, with its reason, where the builder matched by host or derived it. Since 05:00 on 11 November meteorology/ states its joins on its own nodes (entity, of, source), so those crossings are facts.

Build

node tools/graph-build.mjs            # writes storm.json and tables/*.json
node tools/graph-build.mjs --check    # exits 1 if they are not what the inputs give
node tools/graph-build.mjs --out DIR  # writes DIR/data/graph/... only; no tracked file is touched (the build: --out _site)

The output has no clock in it: the same inputs give the same bytes; as_of is the newest time in the inputs. In storm.json a node is short (a name of at most 140 characters); the long text is in the tables, joined by id. Each file stays under 256 KB (the builder stops if one would not).

Use it