coconutlabs live

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.

elapsed

1.81 days since first cycle

ingesting

0.85 days, gaps subtracted

coverage

47.1 % of elapsed time

poll cycles

1,131 completed

rows

5,788,328 stop events

last hour

337,871 rows

cadence

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.

32 gaps recorded · 22h 57m of ingestion lost in total · largest 12h 12m starting 2026-08-13 05:52:36 UTC

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.

startedendeddurationcycles missedreason 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 completed 1,131
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 cycle2026-08-13 02:31:24 UTCThe clock this page counts uptime from.
distinct routes13Bus routes seen in the feed.
distinct trips3,801Individual scheduled trips observed.
distinct stops728Stops with at least one observation.
labels built11,251Rows in the label layer.
labels abutting a gap602Labels whose window touches an ingestion gap. They are marked, not dropped quietly.
labels with no arrival594Trip stops that never produced a final observation.
disk free35.1 GiBHeadroom 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.