BorderFlow: corridor state for Southern Africa
On this page
In short
- WhatCorridor pressure on the Beitbridge route, where no wait times are published.
- HowDaily port calls at Durban, Beira and Maputo from IMF PortWatch.
- ResultA growing open series; the forecast waits for real labels.
The question
Beitbridge is the busiest inland border in Southern Africa and nobody publishes how long it takes to cross. Hauliers and manufacturers moving goods between South Africa and Zimbabwe plan drivers, fuel and perishables around a queue with no public measurement.
The obvious project is a wait-time forecast. I did not build it, and the reason is the centre of this work.
What it measures, and what it refuses to
There is no public ground truth for crossing times. No agency publishes them and no open dataset holds them. A model trained on nothing can only be scored against nothing, and a forecast with no labels is a guess with a chart on top. Anyone who works the corridor knows what the queue did last Tuesday; a chart that does not would lose them on day one.
So version one forecasts nothing and measures what is labelled: seaport throughput at the three ports that feed the corridor, Durban, Beira and Maputo. IMF PortWatch derives daily port calls and cargo volumes from AIS vessel tracking and publishes them openly. A ship that discharges in Durban on Monday becomes trucks on the N1 later in the week, so the series is a real, checkable signal about corridor pressure.
The border layer gets built by collecting labels, not by modelling. A driver or dispatcher records a crossing in about thirty seconds. Only when there are enough labels to hold out a test set does a forecast get built, and it ships with its error rate measured on crossings it never saw.
Design decisions
The collector never mistakes a network failure, or an error dressed as success, for a day with no ships.
Technical detail
- A network failure is never an absence of shipping. Every run appends a record, with the error text when it fails, and
SourceUnreachableis its own exception type so no caller can confuse the two. - The endpoint is discovered, not hardcoded. Each run resolves the dataset through the ArcGIS Hub API and logs the URL it used.
- An error that arrives with HTTP 200 is still an error. ArcGIS answers malformed queries with a success status and an error in the body; reading that as zero rows would record a fault as a day with no ships.
- Append-only JSONL in git. History is the provenance record, and deduplication by port and day makes reruns idempotent.
What it has found so far
Collection is the product right now. The dataset is worth little on its first day and a great deal after ninety, which is why the schedule runs before the analysis exists.
The chart is drawn from a weekly snapshot of the published series.
Daily port calls at Durban, Beira and Maputo with a 7 day rolling mean, 17 April 2026 to 16 October 2026, 547 observations; the last 7 day means are Durban 7.1, Beira 1.0, Maputo 3.0.
Stack
Technical detail
Python and httpx, collection twice daily on GitHub Actions, 13 tests with no network, code under Apache 2.0 and data under CC BY 4.0.
Links
Want to talk about this work? Email me or download my CV.