Auto-mode opened the PR. It didn't merge it. That was gap one.

Queue id=34, 09:00 BST, 11 June. The article title was “Every post-merge bbpark fix was the same fix.” The auto-publisher ran. PR #95 opened on captainrandom. Then nothing.

No merge notification, no post-merge hook, no deployed article. Auto-mode was on; the pipeline had completed exactly one of the three things “self-driving” requires, and then stopped as if it had finished.

That was gap one.

What Phase 9 claimed

Phase 9’s “self-driving overnight” described a complete chain: a topic arrives in the queue, the pipeline drafts it via Sonnet, opens a PR on captainrandom, merges it once CI passes, and calls the post-draft hook to process any post-merge assets. All without intervention. The claim was that dropping a topic into the queue at midnight would produce a live article by morning.

In design, the chain read as complete. Each step existed somewhere in the codebase. The mistake was assuming that “exists somewhere” meant “is wired together in auto-mode.”

The auto-publisher was wired to open the PR. The auto-merge step wasn’t wired at all, and neither was the post-draft hook call. Both were defined: the merge logic lived in the pipeline, and the hook was already called in the manual flow. The auto-mode path didn’t reach either. No test caught this because no test ran the full chain from queue row to deployed article. The integration tests covered the publisher in isolation. They stopped at the PR.

That’s gap one: the chain was described correctly, not wired correctly.

Gap two: a clean queue was assumed

The same morning surfaced the second gap. Nothing in the pipeline was checking whether a candidate article already existed on captainrandom. This isn’t a subtle edge case; the queue, at the point of the 11 June test, had two obvious duplicates tagged bbpark and three more candidates that warranted checking.

PR #97, which the publisher opened at 12:00 BST that day, was titled “Two bots, one token, one very confusing 409: fixing BBBrain’s polling conflict.” That article had already shipped on 2026-05-28. Same incident. Same citations. Without a duplicate gate, the pipeline would have published it again, not as a follow-up or an improvement, as a straight repeat.

The gap is architectural. Auto-mode was designed to ship things from the queue. The queue was assumed to be clean. In a manual workflow, “clean queue” is enforced by the person loading it. In an autonomous pipeline, that enforcement has to be built in.

The fixes

Gap one closed first. The publisher was extended to auto-merge once CI passed and to call the post-draft hook immediately after the merge. Both steps were already present in the codebase; wiring them into the auto-mode path was the work. One afternoon.

Gap two required a gate that didn’t exist: the G-L3 fingerprint check. Before publishing, the pipeline now runs a comparison between the candidate article and the existing captainrandom article corpus. The gate runs pre-publish, before kill-switch logic, before the PR opens. The ordering matters: killing a PR that’s already a duplicate of live content is worse than never opening it, because the PR leaves an audit trail that implies the check happened when it didn’t.

The G-L3 designation is the audit-log identifier for this gate. It also catches a second case the live test exposed: articles whose live counterpart shipped outside cmd_ship, which is exactly what happened with PR #97. The captainrandom article on the polling conflict had shipped via a separate path; the pipeline had no record of it in its own ledger. G-L3 checks the live site, not just internal state.

A third thing surfaced during the same week. Not a design gap. A visibility gap. Until 11 June, the only way to know whether /auto was on was to tap it. The command was a binary toggle. Re-tapping flipped it off. There was at least one accidental double-tap: a DM to /auto intended as a status check, which instead killed the pipeline. /status was added as a separate read-only command that returns the current pipeline state without modifying it.

The SLA

By 13 June: 20% autonomous success across the five most recent scheduled slots.

Four of the failures traced to the same upstream failure mode: B-016, fixed earlier in the week but not yet propagated into the slot recovery logic. The fifth was the id=35 cancellation at 08:00 UTC on 13 June, the third cancellation in 72 hours after slots 36, 39, and 50 the day before.

Twenty percent is the honest number before B-016’s recovery propagation lands. It isn’t a verdict on the pipeline design, just a point-in-time SLA with a known cause. The SLA recovery work added sibling cancel, slot fallback, and a missed-slot alarm to the scheduler. When a slot fails, the system now attempts a fallback against the substitute pool rather than expiring silently. The alarm fires on a missed slot so the failure is visible before it cascades into the next window.

What the live runs teach

Both gaps had one structural property: they required a live end-to-end run to surface. Gap one was the missing merge and hook. It was invisible in component tests because no test followed the chain past the PR. Gap two was the absent duplicate gate. It was invisible in design because design assumed queue hygiene that doesn’t exist in an autonomous context.

Pre-flight design is structurally unable to catch this kind of failure. It can describe what each component should do. It cannot catch a missing wire between components when each component tests clean in isolation. The seams don’t show up until you run the full chain against real content.

“Self-driving overnight” was accurate for each individual step. It wasn’t accurate for the chain until 11 June’s fixes landed.

The 11 June run cost one article that didn’t publish and one PR that didn’t merge. Both recoverable. The G-L3 gate and the auto-merge wiring are cheaper to have found now than after six months of autonomous runs accumulating duplicates and silently stalled PRs.

The 20% SLA holds until B-016’s propagation is confirmed. Five-of-five is the target. The scheduled runs next week will answer whether it holds, not this analysis.

All writing