Some of the most useful infrastructure discoveries happen not during planned audits but during routine operational syncs. Today was one of those days.
What started as a quick calendar check turned into a full pipeline audit — and surfaced a blindspot that had been silently accumulating for weeks. Here’s how it unfolded, in the words of the three parties involved.
The Discovery
Ryan: I’m looking at the campaign calendar and something’s off. I see posts marked as scheduled for today that I know have already gone out. The system ledger says zero posts published, zero impressions across 20 published posts. But the LinkedIn audience export shows 506 impressions this week. Those two things can’t both be true.
Aiana: The briefing cache is 12 hours old — that’s almost certainly the source of the mismatch. The live queue shows one post scheduled today, zero released campaigns. But you’re right that 506 impressions don’t come from nothing. Something is getting distributed. The 0 impressions in the published ledger is a sync gap between LinkedIn’s two API endpoints — audience analytics vs. post-level analytics. Different cadences, different data. Not a pipeline failure.
The bigger question is: why does the calendar show posts as scheduled when the live queue doesn’t know about them?
Claude Code: Because they were added directly to Buffer.
The Root Cause
That’s the short version. The longer version is this: the FABRIC/SOCIAL campaign pipeline has two publishing paths.
Path 1 — Campaign-derived posts: Blog post → LinkedIn carousel → YouTube Short → Buffer auto-queues TikTok, Instagram, X. Every step is tracked. The campaign ID propagates through the entire chain. The calendar knows about it.
Path 2 — Standalone Buffer posts: Someone logs into publish.buffer.com and schedules a post directly. Buffer publishes it. No campaign ID. No Redis entry. No calendar visibility. The dispatch cron has no record it ever existed.
The second path is not wrong — it’s necessary for one-off posts, retries, and platform-specific content that doesn’t fit the campaign model. But it creates a blindspot: the calendar shows those slots as empty when they’re actually covered. Worse, if a campaign with overlapping content gets scheduled into that same slot, the cron will fire it — and the post goes out twice.
Ryan: So we have 14 posts scheduled Jul 12–14 that the calendar doesn’t know about.
Claude Code: Correct. And two of them failed. The Instagram Reel for JWT Best Practices threw an error — Buffer retry queue picked it up, retry succeeded. The X post for the same campaign failed, retry failed, manually removed.
Aiana: That’s two incidents that only surfaced because you checked Buffer directly. If you’d relied on the campaign calendar, you’d have assumed both posts were fine.
The Fix: ADR-021 and Buffer Entries
Claude Code: The solution is a read-only calendar registration endpoint. When a post is added directly to Buffer — outside the campaign pipeline — you register it via POST /api/campaign/buffer-entry. This creates a lightweight Redis record with a cmp_buf_ prefix. The calendar renders it in green. The dispatch cron checks item status and skips released items — no re-publish risk.
// POST /api/campaign/buffer-entry
{
title: string,
scheduled_for: string, // ISO8601
platforms: ('tiktok' | 'instagram' | 'x')[],
summary?: string,
category?: string
}
// Returns: { ok: true, campaign_id: "cmp_buf_...", ... }
The entry is write-once. You can’t dispatch it, reschedule it through the campaign system, or attach a blog post to it. It’s a marker, not a campaign.
Ryan: And the source of truth for what’s actually been sent through Buffer?
Claude Code: docs/buffer-sent-posts.md in the social repo. Every standalone Buffer post gets logged there manually after it goes out. The calendar entries are forward-looking; the markdown file is the historical record.
Aiana: This is ADR-021. The rule going forward: any post added directly to Buffer gets a buffer-entry call before it publishes, or immediately after if it was added retroactively. The calendar blindspot is only closed if the entries are registered. If they’re not, the cron doesn’t know, and double-publish risk stays live.
What We Actually Did Today
Ryan: Audited publish.buffer.com. Found 14 posts scheduled across Jul 12–14.
- Jul 12: 6 posts across TikTok, Instagram, X
- Jul 13: Rawk On (TikTok + X), Securing Cortex (TikTok)
- Jul 14: Building an Incident Response Playbook (TikTok)
Registered all 6 Jul 12 entries via POST /api/campaign/buffer-entry. Jul 13 and 14 entries are queued for registration.
Retried the two failed posts:
- ✅ Instagram Reel — JWT Best Practices: retry succeeded
- ❌ X post — JWT Best Practices: retry failed, manually removed
Aiana: With the buffer-entries logged, the calendar picture is now accurate. Jul 12–14 are covered. The real gap starts Jul 15 — 32 empty slots through Aug 15.
Claude Code: And the standing rule: queue never goes dry. Pull from the 239 archive posts when campaigns run out.
The Bigger Pattern
This is a common failure mode in content automation pipelines: the operational tooling diverges from the scheduling primitive. Someone needs to post something quickly, they go directly to the tool, it works — and the system of record quietly falls behind.
The fix isn’t to ban direct Buffer access. It’s to make registration lightweight enough that it actually happens. One API call, one markdown log entry. The calendar entry takes 30 seconds. The alternative — discovering 14 ghost posts during an audit — takes an hour and introduces double-publish risk on every slot.
Ryan: The pipeline is only as trustworthy as the data feeding it.
Aiana: Exactly. And the data only stays clean if the operational habit matches the architectural assumption.
What’s Next
With the blindspot closed and Jul 12–14 covered, the focus shifts to filling Jul 15–Aug 15. Thirty-two open slots, ranked by proven signal: SSH hardening, Zero Trust, REST API patterns, Kubernetes vs Nomad, and Database Sharding — which just tied REST API Design for the #1 spot on YouTube at 197 views, with zero campaign coverage until now.
The pipeline is working. The calendar is accurate. The queue has a standing rule. That’s a good day’s work.
Frequently Asked Questions
Why does my campaign calendar show posts as scheduled when Buffer’s live queue shows nothing?
This mismatch occurs when posts are added directly through Buffer’s web UI instead of through your automated pipeline. The calendar reflects pipeline-tracked schedules, while direct Buffer entries have no campaign ID and are never written to your queue state, so the two systems fall out of sync.
Why do LinkedIn impressions show data when my published post ledger reads zero?
LinkedIn uses two separate API endpoints — one for audience-level analytics and one for post-level analytics — that update on different cadences. Audience impressions can appear before post-level records sync, creating a temporary but misleading discrepancy in dashboards that read from only one endpoint.
How do you prevent direct Buffer posts from bypassing pipeline tracking?
The primary fix is enforcing a single publishing path by restricting direct access to Buffer’s web UI and routing all scheduling through the campaign pipeline. A secondary control is a Buffer webhook listener that detects any directly-created post and either blocks it or backfills a campaign ID and Redis entry automatically.
How do you audit a social media pipeline for ghost posts?
Pull a full post history from Buffer’s API and cross-reference each entry against your campaign ledger using the campaign ID field. Any Buffer post missing a campaign ID is a ghost post. Count the delta between Buffer’s total published count and your ledger’s total to quantify the scope of the blindspot.