Publishing slots
Set the times posts usually go out and [s] stops asking for a date:
publishing:
slots:
- "mon 09:30"
- "wed 09:30"
- "fri 09:30"
# or a single "daily 09:00"
The draft dialog then names the next FREE slot in the [s] choice itself, and the prompt offers it: Enter accepts, typing a date overrides it, the cancel word backs out. Free means no other scheduled post is aimed at that exact time, so three drafts written in one evening queue onto three consecutive slots instead of publishing together, and the confirmation says which post goes out before this one.
The offer also names the earlier slots it had to walk past and the post sitting in each, so a queue that seems to skip a day explains itself. The properties dialog of a scheduled draft prints the whole queue for the same reason, with an arrow on the post you are looking at.
Slots only ever suggest. A post scheduled by hand for 14:17 occupies no slot and blocks nobody, nothing moves a post that already has a time, and without the key in config/site.yml the prompt is the plain one it always was. Times follow site.timezone, daylight saving included -- "mon 09:30" is 09:30 on the wall clock on both sides of the change. The publish-scheduled cron still runs on its interval, so a slot publishes within one tick of its time.
Working the queue
./blog.sh queue (also a wizard menu entry) shows every scheduled post in publish order and acts on the one you pick:
[u]/[d]move it a slot earlier or later. Moving exchanges times with the neighbouring post -- the set of occupied times never changes, only which post sits in which. A hand-scheduled 14:17 stays a 14:17. The cursor follows the post you moved, so pressing[u]again carries the same post further.[m]picks the post up and carries it: the arrows then move the post itself through the queue, Enter puts it down and Escape leaves the queue as it was. Carrying from the eighth slot to the second steps the six in between back one slot each, so the same times stay occupied and the whole move is one write instead of one per slot. For a single slot[u]/[d]are quicker;[m]is for the longer trip, and it is offered in a terminal only -- a piped run has[u]/[d]and no screen to carry anything across.[p]publishes it right now, the same flow as publishing a draft by hand (announcement included).[s]asks for a different time, same prompt as scheduling.[n]returns it to the drafts; the post keeps its text, loses only the plan.
When a post leaves the queue -- published now, or removed -- its time is free again, and the screen offers to let the posts behind it each step forward into the gap, every one taking over its predecessor's time. It only offers: a hand-picked date further down may be deliberate, and nothing moves a post's time except you. A post whose time already passed is waiting for the cron and can't be reordered.
If the publishing cron happens to be running at the moment you move something, the move is refused rather than written: the two would be writing the same files, and the cron holds them for a few seconds at a time. Press the key again in a moment.
The preview rebuilds once, when you leave the screen, not after every move.
./blog.sh queue --json prints the queue as data instead -- one row per scheduled post in publish order, with its position, time, slug, year, title and whether its time has already passed -- and acts on nothing. Beside the rows it says when something last ran the queue (scheduler.last_run), or null where nothing ever has: on such a blog a post past its time is nobody's to wait for, and both the screen and the refusal say so and point at ./blog.sh publish <slug>.
