The social feed, the media kit and the community feed are refreshed by scheduled GitHub Actions workflows: hourly for TikTok, Instagram, Bluesky, YouTube and the aggregate platform metrics, every six hours for the Mello Zone articles, every ten minutes for the livestream state. This pass audited that pipeline. The feed-building code was sound. What it could not do was tell anyone when it had stopped.
The refresh had been dead for fourteen days
Every poller writes its output file only when the content changed. That is deliberate — it keeps the repository from accumulating a commit an hour for a timestamp nobody reads. The side effect is that the newest date in the repository is the date of the last new post, which is indistinguishable from a pipeline that has stopped running.
It had stopped running. social-feed.json was last written on 18 September at 09:44 UTC and
media-kit.json on the same day at 14:31, against an hourly schedule — roughly 330 runs that never
reached the commit. poll-media-kit.mjs writes a fresh collection timestamp on every run whether or
not a number moved, so a run that completed could not have left that file untouched.
Three things had to be true at once for this to go unnoticed for a fortnight. The workflow’s own health check runs inside the workflow, so a job that fails earlier never reaches it. The release audit and every delivery check validate the shape of the feed, never its age. And the home and Work pages printed “Feed refreshed September 18” — a label built from the last-content-change date, so a dead pipeline and a quiet fortnight produced the same reassuring sentence.
What the pipeline now records, and what fails
Both pollers record polledAt, the UTC day of the run, in the file they publish. Day granularity
is the point: a quiet week costs one line in Git instead of 168, and a pipeline that stops becomes
visible in the repository within a day.
npm run check:freshness reads only committed public data — no network, no credentials — and
compares it against budgets declared in tools/feed-freshness.json: how old a poll may be for each
feed, which platform metrics must be current, and which are deliberately exempt because
durableSnapshot() strips them from Git on purpose. It runs in three places. In the hourly and
six-hourly workflows, where it names the stalled pipeline even after an earlier step has failed. And
in the weekly health report, which is the only one of the three that can catch the case the others
cannot: a workflow that is disabled, or not running at all.
A waiver mechanism keeps that signal meaningful. A breakage waiting on a credential change rather than a code change is listed with the date it started, what was observed and what would clear it; it prints on every run but does not fail the job, so a red run keeps meaning “something new broke” rather than “the same three things are still broken”.
Three collectors that had quietly stopped
With per-platform coverage actually checked rather than assumed, the committed media-kit snapshot turned out to be publishing figures no longer being collected. TikTok returns videos, so the grant works, but no follower, following, post or like count has ever been collected — the grant is missing the statistics scope. Twitch concurrent viewers refresh while follower totals stopped ten days before the last successful run. Kick viewers refresh and a follower count has never arrived.
None of this was visible on the page, because a panel with an uncollected metric simply shows the previous number with an older date. All three are now listed, printed on every run, and each names the credential change that would clear it.
Four ways a platform could disappear
A platform’s own cached entries are what the site falls back to when a source fails, and four paths through the poller could empty a platform instead.
An authorized call that returned zero items replaced that platform’s cached entries with an empty list and reported success, so a scope change or an upstream hiccup could remove every card for a platform from the home page and the Work panels with every check still passing. An empty response from a configured source is now reported as degraded and the cache is kept; an account with genuinely nothing in it still publishes an empty list.
The YouTube collector required /shorts/ in each link, so every full-length upload was discarded
before it reached the feed. A run of ordinary videos emptied the panel while the source reported a
successful fetch of zero items. All uploads are now kept, newest first, and the Work page section
is titled for what it shows.
The Instagram token refresh was unreachable. Extending a long-lived Instagram token requires doing
it before it expires at sixty days, and the branch that does so required INSTAGRAM_AUTH_MODE to
be set to instagram — a variable the workflow leaves unset, so the default meant the refresh never
ran. The token now extends for every mode except Facebook login, which uses a different endpoint,
and a refusal to extend no longer loses the platform.
TikTok’s refresh token has its own expiry, which was recorded and never read. Once it lapsed, every run would have thrown, fallen back to the cache and said so only in a log nobody opens. It is now checked on every run and reported fourteen days before it expires.
A single transient 503 also used to drop a platform to its cache for a whole hour. Statuses that
mean “ask again” are retried, up to three attempts, honouring Retry-After; a 401 or 403 is a
credential problem and is not.
The publishers can no longer fail invisibly
Two steps publish sanitized aggregates and bounded content samples to the Social Poller Worker.
Both are continue-on-error, deliberately: an unreachable Worker must not stop the site refreshing
its own data. But nothing then checked their outcome, so Social Poller ingestion could have been
broken for weeks behind a green workflow. Their outcomes are now enforced after the commit, so the
site still updates and the run still goes red, and the content publisher prints a one-line summary
naming which platforms published, which await a connection and which are failing.
What is deliberately unchanged
The published feed covers four platforms. Content collectors exist for ten, and the extra six — Twitch, Kick, X, Reddit, GitHub, Facebook — reach the media kit and the Social Poller Worker rather than the rendered feed. Adding them to the site means new authored sections on the Work page, which is Sammy’s decision rather than a defect to fix.
The livestream status file is exempt from the freshness budget by declaration. It records a broadcast state rather than a refresh, and a daily liveness bump would commit a no-op change and re-notify search engines every day for nothing.
Validation evidence
142 delivery tests, 251 built-output tests, 49 Worker and feature tests, 7 feed-delivery tests, the release audit across 33 canonical pages, the browser suite across 33 routes with zero failures, and 76 responsive, keyboard and print checks with zero failures. Ten unit tests assert each poller branch, including every way a platform could vanish, and twelve assert the freshness mechanism — among them ten synthetic failures proving the check can actually fail, and that a poll from earlier today is never reported as stale in any timezone. Measured against the committed snapshot, the crawler-facing surface shows two additions and no changes: this entry’s route and its sitemap record. Not one canonical, robots directive, hreflang, Open Graph value or schema type moved.
