Phase 9 claimed self-driving overnight. The first five slots returned twenty percent.

Queue id=35 expired at 08:00 UTC on 13 June. Third cancellation in 72 hours. Four of the five slot expirations before it had been the same upstream failure mode: one logged as B-016, one that a prior fix had nominally addressed. Fixed in the sense of merged. Not fixed in the sense of validated against a live scheduled run. The pattern across the five slots was not variety of failure; it was the same failure, repeating.

Across those five scheduled slots, the auto-pipeline had completed successfully once. Twenty percent.

Phase 9 had been described, internally, as “self-driving overnight delivery.”

What the claim was

The claim was specific. Queue a row, flip /auto on, come back to a live article. No manual steps between triage and publication. Approval routes through the Telegram bot, merges through the publisher, asset generation through the post-draft hook. The pipeline runs while CJ sleeps.

That is the happy path. Pipelines built around the happy path fail when the happy path is not the common case.

The two gaps Phase 9 missed

The 09:00 BST integration run on 11 June (queue id=34, “Every post-merge bbpark fix was the same fix” → captainrandom PR #95) found both gaps simultaneously.

No auto-merge. The publisher opened the PR and stopped. The pipeline was waiting for a merge that was never coming, because nothing in the publisher triggered it. Self-driving overnight left a PR open at exactly the point where a human hand was still required.

No post-draft hook. After merge, the pipeline was supposed to call the post-draft hook to generate assets. It did not. Assets were absent from the deployed article.

Neither gap was obscure; both sit on the “success” path. Unit tests verify function contracts. End-to-end runs verify sequences. The publisher had strong unit coverage and no end-to-end run before Phase 9 shipped. The gap between those two things is where both failures lived.

The fix landed the same day: the publisher now auto-merges and calls the post-draft hook. The claim had been made on the strength of unit testing, not live validation. The live run found what the units could not.

The duplicate

At 12:00 BST the same day, captainrandom PR #97 opened. Title: “Two bots, one token, one very confusing 409 — fixing BBBrain’s polling conflict.”

It was a duplicate. The same incident, the same citations, had already shipped as a live article on 28 May. The auto-pipeline had generated and opened a PR for a piece that already existed on the target site.

The structural gap: the pre-publish stage had nothing checking the candidate against articles already live on captainrandom. The pipeline treated every queued row as novel content. When a row had been queued from a triage decision made before the deduplication logic existed, nothing in the pipeline stopped it completing.

The queue at that point contained at least two other rows that were obvious duplicates. The G-L3 gate was not a speculative defence against edge cases; it was closing a gap the live queue had already demonstrated.

The fix: G-L3, a fingerprint check against the live site, inserted before the kill-switch that commits to auto-publish. The gate catches articles whose live target was shipped outside the normal cmd_ship flow, which is exactly the scenario PR #97 represented.

Out of scope: catching duplicates that share source material but carry a genuinely different thesis. G-L3 is a fingerprint check, not an editorial judgement.

The accidental double-tap

Also on 11 June, CJ sent /auto twice by accident.

The pipeline had no read-only status surface. The only way to know whether auto-mode was active was to send /auto and observe the response. If the current state was uncertain, the act of checking changed the state. Binary toggle with no query path.

The fix: /status, a read-only Telegram command that returns the current pipeline state without mutating it. Reports whether auto-mode is on, current queue depth, and last run outcome.

The reason this matters is not the accidental double-tap. It is that a pipeline described as self-driving had no way to surface its own state without side effects. Observation and intervention were the same operation. That is not a self-driving system.

What the 20% forced

By 13 June, three slots had expired in 72 hours. A structural response was required rather than another point fix.

The response was SLA recovery: three components shipped together.

Sibling cancel. When a slot expires, the pipeline now cancels sibling rows sharing the same source material. The same failed content cannot cycle into the next slot and fail again.

Slot fallback. When a scheduled slot misses, the pipeline attempts to fill it from the next eligible row in the queue. The slot fires. The SLA is honoured even when the original candidate failed.

Missed-slot alarm. When a slot expires with no content shipped and no fallback available, the pipeline fires a Telegram alert. Previously, the silence that followed a failed slot was indistinguishable from a successful overnight run. That silence is replaced with an explicit signal.

Together these three components shift the failure mode from silent degradation to explicit recovery. The 20% figure was a consequence of building for the happy path; the SLA recovery layer is built for the other 80%.

What “autonomous” now means

Diverging from the editorial-policy problem documented in “Five slots, twenty percent: the substitute pool had no editorial policy”: that piece covered what the substitute pool was selecting. This one covers whether the pipeline could execute the selection it was given.

Both are real problems and they compound. An editorial gate that picks the right article does nothing if the publisher cannot auto-merge it. A publisher that auto-merges does nothing if the duplicate gate lets a reprise through. The failure modes are independent.

What the rebuild has produced is not a self-driving pipeline. It is a pipeline with explicit failure modes, explicit recovery paths, and an explicit signal when neither is sufficient. The difference from the original claim is not cosmetic. A self-driving system handles edge cases silently. This system handles them loudly, by design, because the alternative was a 20% success rate that looked like silence until CJ happened to check.

The next five scheduled slots will say more than any of this can.

All writing