When the Blog Queue Runs Dry, the Repository Should Tell You
A queue-health issue can make the boundary between finished content, scheduled posts, and human editorial judgment visible.
The queue-health issue arrived with an unusually specific complaint. On July 27, 2026, it reported that there were zero unpublished blog posts left, the last scheduled date was January 7, 2025, and no next article existed.
It was a small automation system doing its job and reporting that the human part of the system had not happened yet.
The alert was the feature
The blog queue check is intentionally modest. It reads one JSON file, counts dates after the check date, and maintains one GitHub issue when the runway gets too short. It cannot write a post or change a publication date. Deployment is outside its job as well. The issue is a handrail.
That distinction matters because publication has two stages. A Markdown file can sit safely in frontend/content/blog/ for review. Adding it to the manifest puts the source in the application bundle and assigns a UTC date. A shared request-time gate then keeps it off the index, direct route, feed, and sitemap until that date arrives. The Worker bundle still has to deploy ahead of time, but crossing the date boundary needs no second deploy.
Internal issue #1357 made that boundary visible. Its numbers were enough to act: zero future entries, a final date more than a year in the past, and no article waiting for a freshness review.
One manifest, two jobs
The schedule manifest is the calendar and the input to the publication gate. Each entry carries a slug, title, UTC date, description, author, reading time, and a path to the Markdown source. The build script uses the same list to generate the data consumed by the blog pages, index, feed, and sitemap.
There is no separate database hiding a second version of the calendar. That is deliberate. When a post appears on the index, in RSS, or in the sitemap, those surfaces should be reading the same record.
The build step also rejects unfinished sources. A scheduled article cannot contain the special markers used for unsourced autobiographical details and incomplete drafts. It is a small rule, but it prevents the queue from becoming a place where half-written intentions quietly turn into public pages.
Cadence is a constraint
Future entries have to be exactly seven days apart. That does not mean a post will magically be ready every week. It means that once the calendar is filled, an accidental two-day gap or three-week jump fails loudly instead of becoming the new schedule by default.
The distinction is useful for any content system. A cadence check can validate spacing. It cannot validate whether an article is worth publishing, whether a product detail changed yesterday, or whether a link still says what the article says. Those remain editorial and operational decisions.
The queue-health script has a similarly plain threshold: fewer than three future posts is low runway. The next post also gets a freshness review when it is within seven days. Those checks answer two different questions. Do we have enough prepared work, and is the next prepared piece still accurate?
What the workflow leaves to a person
The weekly-cadence work, recorded in internal PR #1343, added the validator, the health script, the issue maintenance workflow, and the RSS route. It also left the queue seeded with the two existing posts on purpose. The first alert was supposed to create an operator task, not hide the fact that a refill was needed.
That is a better boundary than pretending that a schedule is self-sustaining. Someone still has to find a real story in the build, check the mutable details, write the article, and decide that it is ready to be public. The automation handles repetition around those decisions: date arithmetic, source validation, issue deduplication, and a predictable report.
There is a useful habit in that split. Keep the parts that can be made deterministic boring and strict. Keep the parts that require judgment visible. A queue with three future dates is healthier than an empty queue, but it is not proof that three good articles exist.
The repair for this queue is a refill of the manifest with finished sources, a deploy before the first due date, and the same checks that will eventually tell us to refill it again. The request-time gate handles each UTC boundary after that.
Source records
- Internal issue #1357, the scheduled blog queue alert.
- Internal PR #1343, the weekly-cadence blog system.
- Internal PR #1368, the UTC publication gate.
- Internal
docs/BLOG.md, the blog publishing runbook.