At noon today the phase whose whole job is catching what the other phases missed ran clean:
SUPERVISE findings=0 flags=0 notes=0 rows=17 runs=6 # exit 0
Seventeen engagement rows, six worker runs, nothing wrong with any of them. That line is honest. Every check behind it did real work — caps, duplicate text, invented numbers, pacing, run counts against logged rows. It is also, at that exact minute, describing a day in which a scheduled YouTube video had just failed to publish.
It could not see the failure because it was not looking at the queue. It reads
engagements and it reads runs. A post row sitting in failed is neither.
What was actually broken
Three rows, found at 15:00 by a session I ran by hand from the laptop because I wanted to audit the day, not because anything had alerted:
- The 13:30 Threads post, row
c47f43ce:failed. - The 12:00 YouTube video, row
b5fec5d8:failed,asset_not_found— and the asset was not missing.fda03445resolved tonever-fired-web.mp4with a working signed URL when I read it at 14:35. - Yesterday's 19:30 Instagram reel, row
cedadac9: stillscheduled, 24.5 hours past its slot. That one has a known cause —armDueRowsinlib/social/sweep.tsre-arms only rows whoseqstash_message_idis null, and this row holds one, so nothing was ever going to fire it.
Every phase that day reported success and was telling the truth about its own
step. threads-post at 12:30 scheduled a row and checked the platform and
correctly got nothing back; the row failed after it. Each phase ended where
its own work ended.
The error message was wrong four times out of five
Two of those rows carried this string:
stranded in publishing — may already be live, verify on the platform before retrying
Which reads like a warning and functions as a shrug. So I stopped believing it and started opening the profile. threads.com/@amargupta.tech at 14:57: the 13:00 reel was newest, and none of the caption's four distinctive phrases appeared anywhere on the page. Nothing was live. No double-post risk. Re-queue it.
By the end of the day that had happened five times. The 18:55 Threads post
failed with getConnection(threads): Gateway Timeout — a read of the
connection row, thrown before Threads is called at all. Verified not live at
18:57, retried, live at 18:58. The 19:30 Instagram reel stranded the same way;
verified at 20:12 against a profile still holding the same six posts it held at
18:40. Five stranded publishes in one day, and in four of them the "may already
be live" was not live.
That phrasing is doing damage. A message that says maybe transfers the whole
cost onto whoever reads it, every single time, forever. The publish path knows
whether it got a platform_post_id back. On these rows it was null. It could
say so.
The fix, and the thing the fix taught
supervise now reads the queue too (ef579f6). The 17:00 run was the first
with it:
SUPERVISE findings=17 flags=2 notes=15 rows=46 runs=14 posts=129 # exit 1
129 queue rows — 104 scheduled, 18 published, 5 draft, 2 failed. Both failed
rows were already known, already explained in the log, and each already had a
replacement row — which is the right outcome for a first run. It saw what I had
seen by hand two hours earlier. It also checked the things I would have
forgotten: no row stuck in publishing, and no scheduled row anywhere in the
129 with a slot in the past.
The part I want to remember is not the missing check. It is why it was
missing. Every check supervise had was a check on whether a phase did its
work. Comment count against the cap. Run count against logged rows. Text
against yesterday's text. Not one of them asked whether the work had any
effect, because effects land somewhere else — on a platform, in a queue row,
in a platform_post_id — and the monitor only knew about the places the worker
writes to itself.
A system that reports on itself will tell you the truth about itself indefinitely. Mine did. Six runs, all genuinely fine. Zero findings, correctly.
Without that manual audit both failures would have surfaced at tomorrow
morning's 08:30 phase, about twenty hours late, and I would have read them as
"yesterday was quiet" rather than "yesterday's publishes died." The second
half of today caught two more within the hour — the 18:55 one because the phase
stayed for its own slot instead of ending on scheduled, the 19:30 one because
the nightly check now opens the profile.
Staying to watch is not a check you can automate away. But the twenty-hour version is not a monitoring gap. It is a monitor that was asked the wrong question, and answered it perfectly.
