The Facebook auto-publish rail works — the real problem was three posting systems running at once with no coordination.
The reported bug ('scheduled clips never post') was a misread of how n8n waits work. While confirming the fix, a bigger issue surfaced: old schedulers were never turned off, so they collided with the new rail and produced a burst of posts including a duplicate. Source stopped, duplicate removed, future dupes auto-guarded.
6-layer thinking chainChuỗi tư duy 6 tầng
"long-wait executions never post — the webhook returns 200 but nothing shows up; fix it."
Why posts came out in a burst: three rails, no shared brain
Publishing was being driven by three independent systems that didn't know about each other. Each one, on its own, behaved correctly. Together, with no shared coordination, they piled posts onto the same evening window.
| Technical termThuật ngữ kỹ thuật | Plain nameTên dễ hiểu | RoleVai trò |
|---|---|---|
launchd agents (clip-drip, jun22-26, w04b-w04c, w05bc) | Old Mac timers | Pre-n8n schedulers that fired backlog clips on their own daily; never switched off. |
cron twv-publish-poller.py (*/10) | 10-minute poller | Checked for approved content every 10 minutes and published it — a second independent publisher. |
n8n TWV-VID-FB webhook | New direct rail | The cap-free Facebook publisher this project built; the manual fires this session went here. |
in-memory Wait node | Parked timer inside n8n | Holds a scheduled post in memory until its time; invisible to the API until it fires — the source of the 'zero waiting' confusion. |
Read it in 30 seconds: three arrows, one target. The old timers and the poller were still alive, and earlier retry bursts had left timers parked inside n8n. They all landed near 20:30, plus the new manual fires — so the page got a cluster, including one clip posted twice.
What happened, in order
Layered decision cardsCác quyết định theo tầng
Artifact mapBản đồ tệp tạo ra
| PathĐường dẫn | WhatLà gì | Who reads itAi dùng |
|---|---|---|
scripts/twv-automation/wp_twv.py | Added normalize_due (forces +07:00), fire_n8n, schedule_n8n | Reusable, format-correct n8n caller |
scripts/twv-automation/twv-n8n-distribute.py | New CLI to fire a clip to the n8n rail by id + due time | Operator tool for cap-free posting |
scripts/twv-automation/twv-dupe-guard.py | Deletes FB videos inside a given ICT time window on a date | Auto-cleanup of the 2 parked dupes |
crontab (Jun24 & Jun25 20:43) | Two one-shot dupe-guard runs | Removes w04b/w04c dupes when old timers fire |
twv-clip/jun23-power-cuts/beatsheet.en.json | Reframed to 'Lock reliable Q3 capacity' + skyline cover | Pro-Vietnam framing fix; re-rendered + scheduled Jun25 |
DISABLED launchd + cron | clip-drip, jun22-26, w04b-w04c, w05bc + 10-min poller | Stopped the mass-post source (reversible) |
- Top up Gemini TTS and/or ElevenLabs credits — both are at zero, so clip voiceovers currently fall back to the free Edge voice (good, not premium).
- Watch the Facebook page on Jun24 and Jun25 around 20:30-20:45: the dupe-guard should delete the 20:30 re-post and leave the 20:45 post. Log: scripts/twv-automation/content/dupe-guard.log.
- Decide the long-term owner of publishing: keep the old launchd/cron timers OFF and let the n8n rail own it, or formally re-enable a single scheduler. They are currently disabled (reversible via launchctl load -w and the crontab backup at /tmp/twv-cron.bak).
- If you want the parked dupes gone for certain rather than guarded, an n8n restart on the VPS flushes them — but it also clears the two legitimate scheduled posts, which would then need re-firing.