ingestion status · snapshot published 2026-08-14 21:53:00 UTC
Ingestion status.
One poller, one Postgres, one apartment. It polls the MBTA V3 API on a fixed interval, writes every observation, and keeps a ledger of every time it stopped.
1.81 days since first cycle
0.85 days, gaps subtracted
47.1 % of elapsed time
1,131 completed
5,788,328 stop events
337,871 rows
66.6 seconds per cycle
Snapshot published 2026-08-14 21:53:00 UTC, which is 2 minutes ago. Publisher interval 5 minutes as configured. This page calls a snapshot stale after 15 minutes and says so rather than showing the number as current.
the record of interruptions
The gap ledger
Every interruption in ingestion, with when it started, when it ended, how long it lasted and how many polling cycles it cost. A status page that can only show green is not a status page. This is the part worth reading.
Those 32 rows run into each other end to end, so they are 11 continuous outage windows rather than 32 separate incidents. The total above is the merged wall clock time, so no second is counted twice.
| started | ended | duration | cycles missed | reason as recorded |
|---|---|---|---|---|
| 2026-08-14 20:20:02 UTC | 2026-08-14 20:20:05 UTC | 3s | 0 | upstream unreachable (3 of 3 batches) |
| 2026-08-14 13:14:06 UTC | 2026-08-14 13:22:19 UTC | 8m 13s | 6 | no poll recorded |
| 2026-08-14 13:02:04 UTC | 2026-08-14 13:14:06 UTC | 12m 2s | 10 | no poll recorded |
| 2026-08-14 12:30:02 UTC | 2026-08-14 13:02:04 UTC | 32m 2s | 28 | no poll recorded |
| 2026-08-14 11:57:25 UTC | 2026-08-14 12:30:02 UTC | 32m 37s | 28 | no poll recorded |
| 2026-08-14 11:38:39 UTC | 2026-08-14 11:57:25 UTC | 18m 46s | 16 | no poll recorded |
| 2026-08-14 11:00:08 UTC | 2026-08-14 11:38:39 UTC | 38m 30s | 34 | no poll recorded |
| 2026-08-14 10:30:05 UTC | 2026-08-14 11:00:08 UTC | 30m 4s | 26 | upstream unreachable (1 of 3 batches) |
| 2026-08-14 10:04:59 UTC | 2026-08-14 10:30:05 UTC | 25m 5s | 22 | no poll recorded |
| 2026-08-14 09:16:26 UTC | 2026-08-14 10:04:59 UTC | 48m 33s | 43 | no poll recorded |
| 2026-08-14 08:58:50 UTC | 2026-08-14 09:16:26 UTC | 17m 37s | 15 | no poll recorded |
| 2026-08-14 08:23:16 UTC | 2026-08-14 08:58:50 UTC | 35m 34s | 31 | no poll recorded |
| 2026-08-14 07:46:18 UTC | 2026-08-14 08:23:16 UTC | 36m 58s | 32 | no poll recorded |
| 2026-08-14 07:30:06 UTC | 2026-08-14 07:46:18 UTC | 16m 12s | 14 | upstream unreachable (1 of 3 batches) |
| 2026-08-14 06:57:09 UTC | 2026-08-14 07:30:06 UTC | 32m 56s | 29 | no poll recorded |
| 2026-08-14 06:22:24 UTC | 2026-08-14 06:57:09 UTC | 34m 45s | 30 | no poll recorded |
| 2026-08-14 06:03:59 UTC | 2026-08-14 06:22:24 UTC | 18m 25s | 16 | no poll recorded |
| 2026-08-14 05:45:54 UTC | 2026-08-14 06:03:59 UTC | 18m 5s | 15 | no poll recorded |
| 2026-08-14 04:54:43 UTC | 2026-08-14 05:45:54 UTC | 51m 12s | 45 | no poll recorded |
| 2026-08-14 04:21:13 UTC | 2026-08-14 04:54:43 UTC | 33m 30s | 29 | no poll recorded |
| 2026-08-14 03:31:30 UTC | 2026-08-14 03:33:12 UTC | 1m 43s | 0 | upstream unreachable (1 of 3 batches) |
| 2026-08-14 01:56:50 UTC | 2026-08-14 02:11:25 UTC | 14m 34s | 12 | no poll recorded |
| 2026-08-14 01:44:06 UTC | 2026-08-14 01:56:50 UTC | 12m 45s | 10 | no poll recorded |
| 2026-08-14 01:11:37 UTC | 2026-08-14 01:44:06 UTC | 32m 28s | 28 | no poll recorded |
| 2026-08-14 00:51:35 UTC | 2026-08-14 01:11:37 UTC | 20m 2s | 17 | no poll recorded |
| 2026-08-14 00:46:31 UTC | 2026-08-14 00:50:11 UTC | 3m 40s | 2 | no poll recorded |
| 2026-08-13 19:01:49 UTC | 2026-08-13 19:19:42 UTC | 17m 52s | 15 | no poll recorded |
| 2026-08-13 05:52:36 UTC | 2026-08-13 18:05:30 UTC | 12h 12m | 659 | no poll recorded |
| 2026-08-13 04:39:21 UTC | 2026-08-13 04:39:25 UTC | 5s | 0 | poll failed |
| 2026-08-13 04:38:07 UTC | 2026-08-13 04:38:12 UTC | 5s | 0 | poll failed |
| 2026-08-13 04:37:00 UTC | 2026-08-13 04:37:05 UTC | 4s | 0 | poll failed |
| 2026-08-13 04:27:13 UTC | 2026-08-13 04:27:17 UTC | 4s | 0 | poll failed (3 of 3 batches) |
A gap opens when a polling cycle does not land on schedule and closes when cycles resume. The reason column is the string the poller wrote at the time, not a summary written afterwards.
The ledger reconciles
The check that decides whether any of this is worth reading. If the gap ledger were decorative, the cycles it claims were missed would not add up to the cycles that are absent.
cycles the ledger says were missed 1,212
the two together 2,343
elapsed divided by the measured cadence 2,343
difference -0 cycles, against a tolerance of 47
Those two totals land on each other inside the tolerance, so the missing time is accounted for rather than quietly dropped. The tolerance is 2 percent of the expected count or 5 cycles, whichever is larger, because the cadence is a mean and not a fixed tick.
The publisher's own days_running figure differs from the interval between its two timestamps by 10 seconds, which is the lag between measuring and writing. The elapsed figure above is the interval, so it sits on the same clock as the gap rows.
elapsed = published_at minus first_cycle_at, falling back to days_running x 86400 if either timestamp is unreadable. ingesting = elapsed minus the recorded gaps, with overlapping intervals merged before they are added up. expected cycles = elapsed / cadence_seconds, and cadence_seconds is a mean, so that count is good to a few cycles and not to one. every input is a column the publisher wrote.
coverage and labels
What is in the warehouse
| first cycle | 2026-08-13 02:31:24 UTC | The clock this page counts uptime from. |
| distinct routes | 13 | Bus routes seen in the feed. |
| distinct trips | 3,801 | Individual scheduled trips observed. |
| distinct stops | 728 | Stops with at least one observation. |
| labels built | 11,251 | Rows in the label layer. |
| labels abutting a gap | 602 | Labels whose window touches an ingestion gap. They are marked, not dropped quietly. |
| labels with no arrival | 594 | Trip stops that never produced a final observation. |
| disk free | 35.1 GiB | Headroom on the machine doing the ingesting. |
Quality gates 4 of 4 passing
The ingestion checks the poller runs against itself: disk headroom, freshness, volume and null rates. The detail below is copied from the snapshot exactly as the machine wrote it.
- ✓ disk 35.1 GiB free on /System/Volumes/Data
- ✓ freshness last poll_runs row -0.0 min ago
- ✓ volume 337871 rows inserted (poll_runs) in the last hour
- ✓ null_rate scheduled_arrival null-rate 4.18% over last hour (14385/344049)
disclosure
How to read this page
Where this runs
The warehouse is Postgres on a Mac in my apartment. It is not a managed cloud service and this page does not pretend it is. The Mac publishes a snapshot of its own counters to a Cloudflare D1 database on a 5 minute interval. This page reads the newest snapshot and shows how old it is, every time.
That is the whole trick, and the failure mode is the point. If the Mac sleeps, loses power or loses network, the snapshot stops moving, the age climbs, and this page says so in plain words instead of showing an old number as if it were current. The threshold for saying so is 15 minutes.
What these numbers are not
- Uptime here counts from the first poll cycle, not from an install date. Today it is a small number and the page prints it to two decimals rather than rounding it into something rounder.
- The cadence is measured, not configured. The interval is set at 60 seconds, and the work inside each cycle pushes the real spacing above that. The measured figure is the one shown.
- This is a single machine with a single power supply. There is no failover. The gap ledger exists because of that, not in spite of it.
Machine readable: /live/status.json carries every field on this page, including the whole gap ledger.