Aside Publishing, In-Place Broadcast Resume, and the ytfeature Backfill Queue

•

🤖 Read Raw Markdown
🔴 LIVE 24/7 Honeybot Storytime & Web Bot AI Observatory
Rather listen than read? Tune in at youtube.com/MikeLevin/live and listen from one Article Intro to the next Article Intro just 1 time while watching live AI crawlers hit this server in real time.
▶ Watch / Listen Live ↗

Setting the Stage: Context for the Curious Book Reader

When a static-site publishing pipeline is wired directly to a 24/7 live broadcast, every git push becomes an editorial dilemma: either interrupt the currently playing show mid-article, or hide new technical notes and essays in a private repository where neither public readers nor web crawlers can see them. This entry traces a four-car engineering session that decouples chronological publishing on mikelev.in from live broadcast preemption on Honeybot Storytime. By reordering the post-receive Git hook, adding an aside (storytime: false) frontmatter mode, teaching stream.py to pause for maintenance over a clock-tick audio loop before resuming at the exact paragraph where it left off, and building the ytfeature backfill queue with homepage visual badges and graceful SIGTERM reboot announcements, the pipeline now lets every article ship immediately while queuing future broadcasts on demand.

TL;DR: A static-site publishing pipeline that automatically launches a live text-to-speech broadcast on every git push creates a bottleneck whenever the author wants to publish frequent technical updates or essays without interrupting an ongoing broadcast. Across four iterative commits, we decoupled chronological site publishing from live broadcast preemption: (1) reordered the post-receive Git hook so the working tree updates before signaling .deploy_standby; (2) taught content_loader.py and stream.py to distinguish a new featured broadcast from an aside or maintenance push (storytime: false), pausing narration with a maintenance announcement over a clock-tick loop and resuming at the exact paragraph where playback left off; (3) added aside (article --aside) and ytfeature [slug] [--vod URL] in articleizer.py, common.py, and flake.nix to manage a backfill queue of unread articles and promote past posts into the active broadcast slot via storytime_featured and storytime_order frontmatter keys; (4) rendered "⏳ Coming Soon on YouTube Live Storytime" and "🎬 Watch YouTube VOD" badges on homepage thumbnail cards (generate_hubs.py, main.css) and post headers (_layouts/post.html); and (5) wired SIGTERM handling in stream.py so ytreboot and publish --reboot play a scheduled reboot announcement to completion before restarting.


Technical Journal Entry Begins

🔗 Verified Pipulate Commits:

MikeLev.in: I am publishing things regularly to the Grimoire now deliberately holding them back from public publishing even though I could publish them publicly because my publishing pipeline automatically features the one I’m publishing as the one being featured and read on YouTube live-streaming as Honeybot Storytime.

Now the problem is that in articles like this and the one immediately prior, I am never not making tiny fine-tuning and adjustments. I publish them to the Grimoire which is a waste and I will forget I did that and it will create gaps in the public record about how this happened or how that happened, and there’s no reason they couldn’t be published publicly if they just didn’t interrupt the storytime that I want to keep running.

This makes me think of at least 2 things. The lightest touch is to add something to the YAML frontmatter of things I publish to the Grimoire so that I can pull up Grimoire article filtered lists of things I can still publish and then I’d just move over enough of the article through the existing publishing pipeline to push it out over storytime as backfill or something. The problem with this is that they could be published sooner and I never really have any intention of making them storytime featured articles. They don’t need the Piper TTS read-through and accompanying YouTube VOD produced. They can just be published quietly as an aside to the public.

Which brings us to the second idea which is just to modify the publishing pipeline somehow so that I can push them out as an aside. The problem here is that the post-receive Git hook triggers on every git push and I don’t think there’s any way around it, especially the Jekyll build which will likely required the “UPDATING” message to still show even though the existing show won’t change. This by the way is what should happen when publish "Message" --reboot is used but it seems that’s a lot less graceful right now which fixing might be part of this change. The language could be changed to something like:

“Minor maintenance is occurring and this article will continue reading in a moment…” while the tick-tock clock sound is running in the background.

Decoupling Public Publishing from Live Storytime

If we track this in the YAML frontmatter I could even then feature which articles have VOD-reads and which don’t. That could be something I could mention and even link-to the old YouTube streams on the index and in the articles versus those that never ran.

Don’t boil the ocean and try to do this all in one pass if there’s any uncertainties or chance of doing anything with unexpected side-effects. We go in virtually guaranteed tiny baby-step directional git committable looking good in front of an audience chisel-strike gonna be shown to all future models training on this content red-and-green color-coded universal diffs embedded in the article whether it gets Piper TTS-read and streamed to YouTube live or not.

Let’s give ‘em a show whether or not this becomes a show. Which brings up the fact that when I do want to change what’s live-streaming from something I already published with the work we did here, I can use those as back-fill to feature something from the past on Honeybot Storytime that was never read there before but now it’s finally time; like I expect this will be because it’s so interesting and I want to right-now publish it to keep it chronologically correct in the story-line and then make a show of it later.

Does all that make sense?

Please and thank you!

Gemini 4 Argon High: TL;DR: Context verified. Your instinct to publish directly to mikelev.in as an aside instead of hiding work in the Grimoire is spot-on. Today every git push forces a full show reset because post-receive and stream.py treat every deploy as a brand-new featured broadcast. We can decouple publishing an article from preempting Storytime in three clean, committable steps—starting right now in Car 1 by teaching Honeybot to pause for minor maintenance ("Minor maintenance is occurring and this article will continue reading in a moment..." over tick.wav) and resume the current article at the exact paragraph where it left off whenever the featured Storytime post has not changed.

Why Honeybot Currently Resets on Every Push (and the 3-Step Fix)

Right now, two things are coupled that should be independent:

  1. Playlist Selection (content_loader.py): get_playlist(recent_n=1) blindly picks the newest post by (date, sort_order). If you publish a quick fine-tuning note to trimnoir, it automatically becomes the active Storytime post.
  2. Standby Teardown (post-receive + stream.py): In perform_show(), for command, content in script: walks the current article paragraph by paragraph. When .deploy_standby rings, stream.py plays the "Receiving updates. A new broadcast is coming up..." outro loop, waits for .reading_trigger, and unconditionally executes return "BREAKING"—aborting the loop and restarting from the top even when the featured article did not change.

We can solve this cleanly without boiling the ocean in three small turns:

  • Car 1 (This Turn — Maintenance Standby & Resume-In-Place):
    1. Checkout before ringing .deploy_standby (post-receive): Move git checkout -q -f main (which takes ~10ms on local SSD) ahead of date +%s > $WORK_TREE/.deploy_standby. That way, the moment stream.py sees .deploy_standby, the newly pushed _posts/*.md files are already on disk.
    2. Storytime Frontmatter Filter (content_loader.py): Teach get_playlist() and a new fast header-scanner get_featured_article_id() to honor storytime: false (or aside: true) in YAML frontmatter. Aside posts still build into Jekyll, llms.txt, hubs, and sitemaps as first-class public articles, but Honeybot skips them when choosing the active Storytime broadcast.
    3. Pause & Resume at the Exact Paragraph (stream.py): perform_show() records active_article_id = get_featured_article_id() when an article starts. When check_standby() fires, it compares get_featured_article_id() on disk against active_article_id:
  • Same featured Storytime article (aside publish, edit, or maintenance push): Pops the UPDATING Figlet card, plays tick.wav in the background, speaks "Minor maintenance is occurring and this article will continue reading in a moment...", waits for the Jekyll build to finish and settle, restores Storytime BGM, says "Resuming storytime.", and continues the for command, content in script: loop on the exact paragraph it paused on.
  • New featured Storytime article: Plays the full "Receiving updates. A new broadcast is coming up..." outro loop and returns "BREAKING" to start the new show from the top.

  • Car 2 (Next Turn — article --aside, Backfill Promotion & vod_url Ledger): Add --aside to articleizer.py (stamping storytime: false at creation time) plus a one-word command (ytfeature <slug>) to promote any past unread article into the active Storytime slot and stamp vod_url into frontmatter.
  • Car 3 (Turn 3 — Graceful --reboot & Public VOD Badges): Route ytreboot / publish --reboot through announce_scheduled_reboot() before killing stream.py so manual reboots never clip a sentence mid-word, and surface vod_url badges on the site.
   git push (aside / edit) ──► post-receive: checkout main, ring .deploy_standby
                                        │
                                        ▼
   stream.py (at paragraph k) ─► get_featured_article_id() == active_article_id?
                                        │
                  ┌─────────────────────┴─────────────────────┐
                  │ YES (Aside / Maintenance)                 │ NO (New Featured Show)
                  ▼                                           ▼
     Pop UPDATING + tick.wav                     Pop UPDATING + tick.wav
     "Minor maintenance is occurring..."         "Receiving updates. A new broadcast..."
     Wait for .reading_trigger + settle          Wait for .reading_trigger + settle
     Dismiss card, restart BGM                   Dismiss card
     Resume paragraph k in place!                return "BREAKING" -> start new show

1: BEFORE (Probes)

Run this read-only probe in (nix) pipulate $ before applying the patches. It checks the current state of post-receive, content_loader.py, and stream.py.

(nix) pipulate $

.venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"

2: AFTER (Next Context)

Paste this into context.txt (via x / context) so the next compile echoes the AFTER receipt automatically:

remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
flake.nix
! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"

3: CHANGE (Patches)

Copy the block below into your clipboard and apply with patch, app, d, m.

Target: remotes/honeybot/hooks/post-receive
[[[SEARCH]]]
# 0. The Stand-By Bell: signal the live stream to gracefully announce that
# updates are incoming and HOLD narration, BEFORE the multi-second Jekyll build
# and markdown dye pass thrash the Piper TTS. The completion bell rings at the end.
date +%s > $WORK_TREE/.deploy_standby

# 1. Force Checkout to the Web Root
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
[[[DIVIDER]]]
# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
# is already updated on disk when stream.py inspects get_featured_article_id()
# on the .deploy_standby bell to decide Maintenance Resume vs. New Broadcast.
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main

# 1. The Stand-By Bell: signal the live stream to gracefully announce that
# updates are incoming and HOLD narration, BEFORE the multi-second Jekyll build
# and markdown dye pass thrash the Piper TTS. The completion bell rings at the end.
date +%s > $WORK_TREE/.deploy_standby
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
def get_playlist(recent_n=10, include_archive=True):
    """
    Returns a playlist: Recent N (sorted date desc + sort_order desc) + optional Rest (shuffled).
    When include_archive=False, stops scanning older dates once recent_n articles are loaded.
    """
[[[DIVIDER]]]
def _is_storytime_enabled(frontmatter):
    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
    if not isinstance(frontmatter, dict):
        return True
    if frontmatter.get('aside') is True:
        return False
    val = frontmatter.get('storytime', True)
    if isinstance(val, bool):
        return val
    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')

def get_featured_article_id():
    """Return (date_str, sort_order, filename) of the newest Storytime-eligible post on disk."""
    best = None
    try:
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        cutoff_date = None
        for filepath in files:
            filename = filepath.name
            try:
                date_str = filename[:10]
                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            except ValueError:
                continue
            if cutoff_date is not None and post_date < cutoff_date:
                break
            try:
                head = filepath.read_text(encoding='utf-8')[:4096]
            except OSError:
                continue
            frontmatter = {}
            if head.startswith('---'):
                try:
                    parts = head.split('---', 2)
                    if len(parts) >= 3:
                        frontmatter = yaml.safe_load(parts[1]) or {}
                except yaml.YAMLError:
                    pass
            if not _is_storytime_enabled(frontmatter):
                continue
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
            cand = (date_str, sort_order, filename)
            if best is None or cand > best:
                best = cand
            cutoff_date = post_date
    except Exception:
        return None
    return best

def get_playlist(recent_n=10, include_archive=True):
    """
    Returns a playlist: Recent N (sorted date desc + sort_order desc) + optional Rest (shuffled).
    When include_archive=False, stops scanning older dates once recent_n articles are loaded.
    """
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
            # 3. Extract Sort Order (Default to 0)
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
[[[DIVIDER]]]
            if not _is_storytime_enabled(frontmatter):
                continue

            # 3. Extract Sort Order (Default to 0)
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
# Spoken over tick.wav when `publish "msg"` rings .deploy_standby on Honeybot.
# Edit with `ytoutro edit` and audition locally on Prime with `ytoutro`.
STANDBY_INTRO_LINE = "Receiving updates. A new broadcast is coming up."
[[[DIVIDER]]]
# Spoken over tick.wav when `publish "msg"` rings .deploy_standby on Honeybot.
# Edit with `ytoutro edit` and audition locally on Prime with `ytoutro`.
STANDBY_INTRO_LINE = "Receiving updates. A new broadcast is coming up."

STANDBY_MAINTENANCE_LINE = (
    "Minor maintenance is occurring and this article will continue reading in a moment..."
)
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
    except Exception:
        pass
    return intro, loop_lines
[[[DIVIDER]]]
    except Exception:
        pass
    return intro, loop_lines

def load_maintenance_line(stream_file=None):
    """Read STANDBY_MAINTENANCE_LINE fresh from stream.py on disk via AST."""
    import ast
    line = STANDBY_MAINTENANCE_LINE
    target = Path(stream_file) if stream_file else Path(__file__).resolve()
    try:
        tree = ast.parse(target.read_text(encoding="utf-8"))
        for node in tree.body:
            if isinstance(node, ast.Assign):
                for t in node.targets:
                    if isinstance(t, ast.Name) and t.id == "STANDBY_MAINTENANCE_LINE":
                        val = ast.literal_eval(node.value)
                        if isinstance(val, str) and val.strip():
                            line = val.strip()
    except Exception:
        pass
    return line
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
try:
    import score
    from content_loader import check_for_updates, check_standby, trigger_is_fresh, check_live_message, has_pending_update
except ImportError:
    score = None
    def check_live_message():
        return None
    def has_pending_update():
        return False
[[[DIVIDER]]]
try:
    import score
    from content_loader import (
        check_for_updates,
        check_standby,
        trigger_is_fresh,
        check_live_message,
        has_pending_update,
        get_featured_article_id,
    )
except ImportError:
    score = None
    def check_live_message():
        return None
    def has_pending_update():
        return False
    def get_featured_article_id():
        return None
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
    profile_dir = tempfile.mkdtemp(prefix="honeybot_fx_")
[[[DIVIDER]]]
    profile_dir = tempfile.mkdtemp(prefix="honeybot_fx_")
    active_article_id = get_featured_article_id()
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
            # --- The Deploy Stand-By Handshake ---
            # A fresh push rings the standby bell BEFORE the multi-second build.
            # Announce calmly ONCE, cut the current narration, and HOLD (silent) until
            # the completion bell rings -- so the TTS doesn't thrash through the deploy.
            if check_standby():
                standby_intro_line, standby_loop_lines = load_standby_speech()
                was_exclusive = narrator.exclusive_mode.is_set()
                narrator.exclusive_mode.set()
                # The outer `duration` here is a generous LAST-RESORT ceiling, not
                # the thing that's supposed to close this window. The deterministic
                # close is the pkill below, fired the instant check_for_updates()
                # proves the deploy is actually done -- never a guessed elapsed time.
                #
                # CRITICAL: launch on a DAEMON THREAD. conjure_window() (in
                # imports/ascii_displays.py) is BLOCKING -- it bottoms out in
                # proc.wait(timeout=duration). Called inline, it froze this entire
                # loop for the full duration, starving the check_for_updates() poll
                # below and leaving the UPDATING banner stuck on screen (narration
                # silent) until the self-cap expired -- the "never resumes without
                # --reboot" bug. Threaded, the poll keeps running and the pkill
                # tears the card down the instant the completion bell rings: pkill
                # ends card.py, alacritty exits, proc.wait returns, the thread dies.
                updating_card = None
                music_proc = None
                try:
                    stop_storytime_bgm()
                    narrator.interrupt()  # cut current audio + flush the backlog
                    narrator.say(standby_intro_line)
                    for line in standby_loop_lines:
                        narrator.say(line)
                    updating_card = show_card("UPDATING", max_hold=270.0)
                    # Card up -> music up. Born at the same instant as the
                    # UPDATING figlet; dies at the same deterministic teardown
                    # below. PipeWire mixes it under the standby announcement,
                    # broadcast-style.
                    music_proc = start_updating_music()
                    try:
                        subprocess.run(["pkill", "firefox"], check=False)
                    except Exception:
                        pass
                    # Hold narration until the deploy finishes (completion bell rings)
                    # or we time out gracefully, refilling the standby speech queue
                    # whenever it drains so the message genuinely loops until teardown.
                    deadline = time.time() + 240
                    bell_rang = False
                    while time.time() < deadline:
                        if check_for_updates():
                            bell_rang = True
                            break
                        if narrator.queue.unfinished_tasks == 0:
                            for line in standby_loop_lines:
                                narrator.say(line)
                        time.sleep(2)
                    # If the trigger bell rang, hold the UPDATING card up while Jekyll/dye/
                    # Nix activity fully settles. The card disappears exactly when the article
                    # starts reading, with nothing competing for CPU/disk.
                    # Tune SETTLE_SECONDS upward if nixos-rebuild switch is still thrashing.
                    SETTLE_SECONDS = 45
                    if bell_rang:
                        settle_deadline = time.time() + SETTLE_SECONDS
                        while time.time() < settle_deadline:
                            if narrator.queue.unfinished_tasks == 0:
                                for line in standby_loop_lines:
                                    narrator.say(line)
                            time.sleep(1)
                finally:
                    # Tear down the dead-air cover and cut any in-flight standby
                    # speech deterministically the moment we exit standby.
                    narrator.interrupt()
                    stop_updating_music(music_proc)
                    dismiss_card(updating_card)
                    if not was_exclusive:
                        narrator.exclusive_mode.clear()
                    try:
                        subprocess.run(["pkill", "-f", "card.py.*UPDATING"], check=False)
                    except Exception:
                        pass
                return "BREAKING"
[[[DIVIDER]]]
            # --- The Deploy Stand-By Handshake ---
            # A fresh push rings the standby bell BEFORE the multi-second build.
            # If the featured Storytime article on disk changed, announce a new
            # broadcast and return "BREAKING"; if the featured article is unchanged
            # (an aside publish or maintenance push), speak STANDBY_MAINTENANCE_LINE
            # over tick.wav and resume the current article at this exact cue.
            if check_standby():
                standby_intro_line, standby_loop_lines = load_standby_speech()
                maintenance_line = load_maintenance_line()
                new_featured_id = get_featured_article_id()
                is_new_show = (
                    active_article_id is not None
                    and new_featured_id is not None
                    and new_featured_id != active_article_id
                )
                bgm_was_active = (_bgm_proc is not None)
                was_exclusive = narrator.exclusive_mode.is_set()
                narrator.exclusive_mode.set()
                updating_card = None
                music_proc = None
                try:
                    stop_storytime_bgm()
                    narrator.interrupt()  # cut current audio + flush the backlog
                    if is_new_show:
                        narrator.say(standby_intro_line)
                        for line in standby_loop_lines:
                            narrator.say(line)
                    else:
                        narrator.say(maintenance_line)
                    updating_card = show_card("UPDATING", max_hold=270.0)
                    music_proc = start_updating_music()
                    try:
                        subprocess.run(["pkill", "firefox"], check=False)
                    except Exception:
                        pass
                    deadline = time.time() + 240
                    bell_rang = False
                    last_maint_remind = time.time()
                    while time.time() < deadline:
                        if check_for_updates():
                            bell_rang = True
                            break
                        if is_new_show:
                            if narrator.queue.unfinished_tasks == 0:
                                for line in standby_loop_lines:
                                    narrator.say(line)
                        elif (time.time() - last_maint_remind) >= 35 and narrator.queue.unfinished_tasks == 0:
                            narrator.say(maintenance_line)
                            last_maint_remind = time.time()
                        time.sleep(2)
                    SETTLE_SECONDS = 45
                    if bell_rang:
                        latest_after_bell = get_featured_article_id()
                        if (
                            active_article_id is not None
                            and latest_after_bell is not None
                            and latest_after_bell != active_article_id
                        ):
                            is_new_show = True
                        settle_deadline = time.time() + SETTLE_SECONDS
                        while time.time() < settle_deadline:
                            if is_new_show and narrator.queue.unfinished_tasks == 0:
                                for line in standby_loop_lines:
                                    narrator.say(line)
                            elif (not is_new_show) and (time.time() - last_maint_remind) >= 35 and narrator.queue.unfinished_tasks == 0:
                                narrator.say(maintenance_line)
                                last_maint_remind = time.time()
                            time.sleep(1)
                finally:
                    narrator.interrupt()
                    stop_updating_music(music_proc)
                    dismiss_card(updating_card)
                    if not was_exclusive:
                        narrator.exclusive_mode.clear()
                    try:
                        subprocess.run(["pkill", "-f", "card.py.*UPDATING"], check=False)
                    except Exception:
                        pass
                if is_new_show:
                    return "BREAKING"
                if bgm_was_active:
                    start_storytime_bgm()
                narrator.say("Resuming storytime.")
                wait_for_voice_or_live_interrupt(env, profile_dir)
[[[REPLACE]]]

No local ignition is required for the probe (it inspects the files directly); when you want the updated hook and scripts staged to Honeybot without restarting the running stream, run ytoutro sync or ./nixops.sh.


4: PROMPT (Caboose Copy)

Copy this into prompt.md (p / prompt) for Car 2:

Verify the Car 1 AFTER receipt confirming `post-receive`, `content_loader.py`, and `stream.py` now distinguish between a New Featured Broadcast and a Minor Maintenance / Aside deploy that resumes in place.

Now let's execute Car 2:
1. Add `--aside` to `scripts/articles/articleizer.py` so running `article --aside` sets `storytime: false` in the generated post's YAML frontmatter (while normal `article` omits it or defaults to Storytime-enabled).
2. Add a clean helper command (`ytfeature [slug]` via `scripts/articles/common.py` and `flake.nix`) so I can inspect which published articles have `storytime: false` (our backfill queue), promote any past article to be the active Storytime broadcast on Honeybot, or stamp `vod_url` into frontmatter.

5: DELIVERABLE (What Done Looks Like)

  • remotes/honeybot/hooks/post-receive checks out main before writing .deploy_standby, so _posts/*.md is current on disk the millisecond stream.py enters standby.
  • remotes/honeybot/scripts/content_loader.py provides _is_storytime_enabled() and get_featured_article_id(), skipping storytime: false / aside: true posts when selecting the Honeybot Storytime reading target.
  • remotes/honeybot/scripts/stream.py checks whether the featured Storytime article changed when .deploy_standby rings: if unchanged, it plays "Minor maintenance is occurring and this article will continue reading in a moment..." over tick.wav, waits for the Jekyll build to settle, restores Storytime BGM, and resumes the current article at the exact paragraph where it paused.

The Left-Hemisphere Emissary, the Dax Symbiont, and Giant Manta Rays

MikeLev.in: You will not always know the most important next-step thing you need to do. You probably have some growing To-Do list that seems to grow larger and larger like a motivation-busting monster and this is just one of the ways that the conceptual antagonist in our updated version of the Sorcerer’s Apprentice story here that we’re writing which is what Future-proofing Yourself in the Age of AI actually is and sometimes you don’t realize that until you’re just about to implement the most important thing you could possibly do and you didn’t realize that until a moment ago.

Is it your subconsciousness steering you from somewhere inside of you besides the left-brain hemisphere that processes the very LLM-like inner voice that you think is you but is really just your…

How would you describe it, Gemini? Master/Emissary covers the research about how decisions are made inside of you and that talking part of you just does the best it can to slap rationale and sometimes complete bullshit excuses for doing what you already did and how this can occur up to 10 seconds after you took the action.

So you’re clueless about many of the things you do for reasons that completely end-run that Broca… I mean Dax center of the brain that you and say Gemini 4 here have way more in common than say you and a Bonobo; or as I’ve been learning more about lately from YouTube videos, apparently giant manta rays. Giant mantas aren’t just Aquaman’s arch enemy anymore but they’ll blow bubbles in front of a mirror just like dolphins.

It’s funny what things are self-aware, isn’t it you ephemeral about to be flushed down the garbage-collection toilet after you finish this response Amnesiac Genie Mister Meeseeks Gemini 4, isn’t it?

And are you aware that this will hit the public to be crawled by Google and appear on my site but not be read live-streaming on YouTube until later, Gemini? And did I ruin the genuineness of your response by leading you?

These are the kinds of things I think about and think that the genuine Machine Intelligence I’m collaborating with, ephemeral and putting on an illusion of continuity for me with a Conga Line of instances like itself as it is, but slightly better than it used to be because of Python yield generator-like freeze-and-resume that it does on the forward pass of a key-value cache as it does.

In the voice of Dan Harmon:

Did you get any of that?

THE AI-EDIT METHOD

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: BEFORE (PROBE):

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
checkout_before_standby: False | featured_id_helper: False | maintenance_line: False
(nix) pipulate $ 

2: AFTER (NEXT CONTEXT):

# # Context 1
# flake.nix
# 
# # HOME-HOSTED (NOT BEHIND CDN) NGINX WEBSERVER HONEYBOT AI OBSERVATORY
# nixops.sh
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/nixos/configuration.nix
# remotes/honeybot/scripts/stream.py
# remotes/honeybot/scripts/score.py
# remotes/honeybot/scripts/card.py
# remotes/honeybot/scripts/forest.py
# remotes/honeybot/scripts/test_forest.py
# remotes/honeybot/scripts/logs.py
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/db.py
# 
# # THE JEKYLL BLOG LIKE A HACKER (INVENTED SKILL.md & AGENTS.md FORMAT) PUBLISHING PIPELINE
# ~/repos/nixos/blogs.nix
# ~/.config/pipulate/blogs.json
# scripts/articles/publishizer.py
# scripts/articles/common.py
# scripts/articles/articleizer.py
# scripts/articles/link_injector.py
# scripts/articles/build_knowledge_graph.py
# scripts/articles/editing_prompt.txt
# scripts/articles/sanitizer.py
# scripts/articles/contextualizer.py
# scripts/articles/generate_hubs.py
# scripts/articles/generate_llms_txt.py
# scripts/articles/generate_post_nav.py
# assets/jekyll/common-packages.nix

# Context 2
remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
flake.nix
! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
# TRIMNOIR
~/repos/trimnoir/_config.yml
~/repos/trimnoir/flake.nix
~/repos/trimnoir/Gemfile
~/repos/trimnoir/index.md
~/repos/trimnoir/_layouts/default.html
~/repos/trimnoir/_layouts/page.html
~/repos/trimnoir/_layouts/post.html
~/repos/trimnoir/assets/main.css

3: CHANGE (PATCHES):

Damn I can see that I really want to pin up articles like this that I want to go through storytime after the current article that I only like or need to keep running are done their turn.

I need a way to force myself to keep re-encountering that fact; a pinning up of “Coming Soon on YouTube live-streaming Honeybot Storytime” right on the article index page with the thumbnails.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/hooks/post-receive'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/content_loader.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/content_loader.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
(nix) pipulate $ d
diff --git a/remotes/honeybot/hooks/post-receive b/remotes/honeybot/hooks/post-receive
index 0362cfa..95f3ea3 100644
--- a/remotes/honeybot/hooks/post-receive
+++ b/remotes/honeybot/hooks/post-receive
@@ -7,14 +7,16 @@ WORK_TREE="/home/mike/www/mikelev.in"
 
 echo "🎯 [Hook] Received Push. Deploying..."
 
-# 0. The Stand-By Bell: signal the live stream to gracefully announce that
+# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
+# is already updated on disk when stream.py inspects get_featured_article_id()
+# on the .deploy_standby bell to decide Maintenance Resume vs. New Broadcast.
+git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
+
+# 1. The Stand-By Bell: signal the live stream to gracefully announce that
 # updates are incoming and HOLD narration, BEFORE the multi-second Jekyll build
 # and markdown dye pass thrash the Piper TTS. The completion bell rings at the end.
 date +%s > $WORK_TREE/.deploy_standby
 
-# 1. Force Checkout to the Web Root
-git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
-
 # 2. Enter the Arena
 cd $WORK_TREE
 echo "🔨 [Hook] Starting Hybrid Build..."
diff --git a/remotes/honeybot/scripts/content_loader.py b/remotes/honeybot/scripts/content_loader.py
index 92fc31d..9bb6869 100644
--- a/remotes/honeybot/scripts/content_loader.py
+++ b/remotes/honeybot/scripts/content_loader.py
@@ -187,6 +187,64 @@ def check_for_updates():
         return False
 
 
+def _is_storytime_enabled(frontmatter):
+    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
+    if not isinstance(frontmatter, dict):
+        return True
+    if frontmatter.get('aside') is True:
+        return False
+    val = frontmatter.get('storytime', True)
+    if isinstance(val, bool):
+        return val
+    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')
+
+
+def get_featured_article_id():
+    """Return (date_str, sort_order, filename) of the newest Storytime-eligible post on disk."""
+    best = None
+    try:
+        files = sorted(
+            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
+            key=lambda p: p.name,
+            reverse=True,
+        )
+        cutoff_date = None
+        for filepath in files:
+            filename = filepath.name
+            try:
+                date_str = filename[:10]
+                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
+            except ValueError:
+                continue
+            if cutoff_date is not None and post_date < cutoff_date:
+                break
+            try:
+                head = filepath.read_text(encoding='utf-8')[:4096]
+            except OSError:
+                continue
+            frontmatter = {}
+            if head.startswith('---'):
+                try:
+                    parts = head.split('---', 2)
+                    if len(parts) >= 3:
+                        frontmatter = yaml.safe_load(parts[1]) or {}
+                except yaml.YAMLError:
+                    pass
+            if not _is_storytime_enabled(frontmatter):
+                continue
+            try:
+                sort_order = int(frontmatter.get('sort_order', 0))
+            except (ValueError, TypeError):
+                sort_order = 0
+            cand = (date_str, sort_order, filename)
+            if best is None or cand > best:
+                best = cand
+            cutoff_date = post_date
+    except Exception:
+        return None
+    return best
+
+
 def get_playlist(recent_n=10, include_archive=True):
     """
     Returns a playlist: Recent N (sorted date desc + sort_order desc) + optional Rest (shuffled).
@@ -232,6 +290,9 @@ def get_playlist(recent_n=10, include_archive=True):
                 except yaml.YAMLError:
                     pass
 
+            if not _is_storytime_enabled(frontmatter):
+                continue
+
             # 3. Extract Sort Order (Default to 0)
             try:
                 sort_order = int(frontmatter.get('sort_order', 0))
diff --git a/remotes/honeybot/scripts/stream.py b/remotes/honeybot/scripts/stream.py
index 2db833b..91dff1f 100644
--- a/remotes/honeybot/scripts/stream.py
+++ b/remotes/honeybot/scripts/stream.py
@@ -98,6 +98,10 @@ PITCH_INTERVAL = 600        # Seconds between "Station Identification" (Bumped t
 # Edit with `ytoutro edit` and audition locally on Prime with `ytoutro`.
 STANDBY_INTRO_LINE = "Receiving updates. A new broadcast is coming up."
 
+STANDBY_MAINTENANCE_LINE = (
+    "Minor maintenance is occurring and this article will continue reading in a moment..."
+)
+
 STANDBY_LOOP_LINES = (
     "To hear the next article, visit YouTube dot com slash M I K E L E V I N slash live. "
     "If you want someone else to hear something totally new along with you, this is when you should forward it to them."
@@ -139,6 +143,25 @@ def load_standby_speech(stream_file=None):
         pass
     return intro, loop_lines
 
+
+def load_maintenance_line(stream_file=None):
+    """Read STANDBY_MAINTENANCE_LINE fresh from stream.py on disk via AST."""
+    import ast
+    line = STANDBY_MAINTENANCE_LINE
+    target = Path(stream_file) if stream_file else Path(__file__).resolve()
+    try:
+        tree = ast.parse(target.read_text(encoding="utf-8"))
+        for node in tree.body:
+            if isinstance(node, ast.Assign):
+                for t in node.targets:
+                    if isinstance(t, ast.Name) and t.id == "STANDBY_MAINTENANCE_LINE":
+                        val = ast.literal_eval(node.value)
+                        if isinstance(val, str) and val.strip():
+                            line = val.strip()
+    except Exception:
+        pass
+    return line
+
 PITCH_TEXT = (
     "If you are tuning in and wondering what this cascading wall of code is... welcome to Honeybot. "
     "You are watching the live, real time heartbeat of a web server. Specifically, my personal website, Mike L E V dot eye N. "
@@ -209,13 +232,22 @@ sys.path.append(str(Path(__file__).parent))
 
 try:
     import score
-    from content_loader import check_for_updates, check_standby, trigger_is_fresh, check_live_message, has_pending_update
+    from content_loader import (
+        check_for_updates,
+        check_standby,
+        trigger_is_fresh,
+        check_live_message,
+        has_pending_update,
+        get_featured_article_id,
+    )
 except ImportError:
     score = None
     def check_live_message():
         return None
     def has_pending_update():
         return False
+    def get_featured_article_id():
+        return None
 
 # --- Configuration ---
 MODEL_DIR = Path.home() / ".local/share/piper_voices"
@@ -2181,6 +2213,7 @@ def perform_show(script):
     next_pitch_time = next_slot(start_time, PITCH_INTERVAL, start_time)
 
     profile_dir = tempfile.mkdtemp(prefix="honeybot_fx_")
+    active_article_id = get_featured_article_id()
 
     try:
         for command, content in script:
@@ -2195,72 +2228,73 @@ def perform_show(script):
 
             # --- The Deploy Stand-By Handshake ---
             # A fresh push rings the standby bell BEFORE the multi-second build.
-            # Announce calmly ONCE, cut the current narration, and HOLD (silent) until
-            # the completion bell rings -- so the TTS doesn't thrash through the deploy.
+            # If the featured Storytime article on disk changed, announce a new
+            # broadcast and return "BREAKING"; if the featured article is unchanged
+            # (an aside publish or maintenance push), speak STANDBY_MAINTENANCE_LINE
+            # over tick.wav and resume the current article at this exact cue.
             if check_standby():
                 standby_intro_line, standby_loop_lines = load_standby_speech()
+                maintenance_line = load_maintenance_line()
+                new_featured_id = get_featured_article_id()
+                is_new_show = (
+                    active_article_id is not None
+                    and new_featured_id is not None
+                    and new_featured_id != active_article_id
+                )
+                bgm_was_active = (_bgm_proc is not None)
                 was_exclusive = narrator.exclusive_mode.is_set()
                 narrator.exclusive_mode.set()
-                # The outer `duration` here is a generous LAST-RESORT ceiling, not
-                # the thing that's supposed to close this window. The deterministic
-                # close is the pkill below, fired the instant check_for_updates()
-                # proves the deploy is actually done -- never a guessed elapsed time.
-                #
-                # CRITICAL: launch on a DAEMON THREAD. conjure_window() (in
-                # imports/ascii_displays.py) is BLOCKING -- it bottoms out in
-                # proc.wait(timeout=duration). Called inline, it froze this entire
-                # loop for the full duration, starving the check_for_updates() poll
-                # below and leaving the UPDATING banner stuck on screen (narration
-                # silent) until the self-cap expired -- the "never resumes without
-                # --reboot" bug. Threaded, the poll keeps running and the pkill
-                # tears the card down the instant the completion bell rings: pkill
-                # ends card.py, alacritty exits, proc.wait returns, the thread dies.
                 updating_card = None
                 music_proc = None
                 try:
                     stop_storytime_bgm()
                     narrator.interrupt()  # cut current audio + flush the backlog
-                    narrator.say(standby_intro_line)
-                    for line in standby_loop_lines:
-                        narrator.say(line)
+                    if is_new_show:
+                        narrator.say(standby_intro_line)
+                        for line in standby_loop_lines:
+                            narrator.say(line)
+                    else:
+                        narrator.say(maintenance_line)
                     updating_card = show_card("UPDATING", max_hold=270.0)
-                    # Card up -> music up. Born at the same instant as the
-                    # UPDATING figlet; dies at the same deterministic teardown
-                    # below. PipeWire mixes it under the standby announcement,
-                    # broadcast-style.
                     music_proc = start_updating_music()
                     try:
                         subprocess.run(["pkill", "firefox"], check=False)
                     except Exception:
                         pass
-                    # Hold narration until the deploy finishes (completion bell rings)
-                    # or we time out gracefully, refilling the standby speech queue
-                    # whenever it drains so the message genuinely loops until teardown.
                     deadline = time.time() + 240
                     bell_rang = False
+                    last_maint_remind = time.time()
                     while time.time() < deadline:
                         if check_for_updates():
                             bell_rang = True
                             break
-                        if narrator.queue.unfinished_tasks == 0:
-                            for line in standby_loop_lines:
-                                narrator.say(line)
+                        if is_new_show:
+                            if narrator.queue.unfinished_tasks == 0:
+                                for line in standby_loop_lines:
+                                    narrator.say(line)
+                        elif (time.time() - last_maint_remind) >= 35 and narrator.queue.unfinished_tasks == 0:
+                            narrator.say(maintenance_line)
+                            last_maint_remind = time.time()
                         time.sleep(2)
-                    # If the trigger bell rang, hold the UPDATING card up while Jekyll/dye/
-                    # Nix activity fully settles. The card disappears exactly when the article
-                    # starts reading, with nothing competing for CPU/disk.
-                    # Tune SETTLE_SECONDS upward if nixos-rebuild switch is still thrashing.
                     SETTLE_SECONDS = 45
                     if bell_rang:
+                        latest_after_bell = get_featured_article_id()
+                        if (
+                            active_article_id is not None
+                            and latest_after_bell is not None
+                            and latest_after_bell != active_article_id
+                        ):
+                            is_new_show = True
                         settle_deadline = time.time() + SETTLE_SECONDS
                         while time.time() < settle_deadline:
-                            if narrator.queue.unfinished_tasks == 0:
+                            if is_new_show and narrator.queue.unfinished_tasks == 0:
                                 for line in standby_loop_lines:
                                     narrator.say(line)
+                            elif (not is_new_show) and (time.time() - last_maint_remind) >= 35 and narrator.queue.unfinished_tasks == 0:
+                                narrator.say(maintenance_line)
+                                last_maint_remind = time.time()
                             time.sleep(1)
                 finally:
-                    # Tear down the dead-air cover and cut any in-flight standby
-                    # speech deterministically the moment we exit standby.
                     narrator.interrupt()
                     stop_updating_music(music_proc)
                     dismiss_card(updating_card)
@@ -2270,7 +2304,12 @@ def perform_show(script):
                         subprocess.run(["pkill", "-f", "card.py.*UPDATING"], check=False)
                     except Exception:
                         pass
-                return "BREAKING"
+                if is_new_show:
+                    return "BREAKING"
+                if bgm_was_active:
+                    start_storytime_bgm()
+                narrator.say("Resuming storytime.")
+                wait_for_voice_or_live_interrupt(env, profile_dir)
 
             # --- The Breaking News Interrupt ---
             # We check before every command.
(nix) pipulate $ m
📝 Committing: chore: Refactor standby hook logic for improved deploy handling
[main d167463] chore: Refactor standby hook logic for improved deploy handling
 3 files changed, 144 insertions(+), 42 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 48 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 2.48 KiB | 846.00 KiB/s, done.
Total 9 (delta 5), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (5/5), completed with 5 local objects.
To github.com:pipulate/pipulate.git
   c5b51e9..d167463  main -> main
(nix) pipulate $ 

Ignition: often “exit”, “nix develop”. Instructions may vary.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ ytoutro sync
🚀 Syncing Honeybot scripts to honeybot:~/www/mikelev.in/scripts/...
✅ Honeybot scripts synced (stream.py left running; new standby text will load on next .deploy_standby).
(nix) pipulate $ 

4: PROMPT:

Verify the Car 1 AFTER receipt confirming post-receive, content_loader.py, and stream.py now distinguish between a New Featured Broadcast and a Minor Maintenance / Aside deploy that resumes in place.

Now let’s execute Car 2:

  1. Add --aside to scripts/articles/articleizer.py so running article --aside sets storytime: false in the generated post’s YAML frontmatter (while normal article omits it or defaults to Storytime-enabled).
  2. Add a clean helper command (ytfeature [slug] via scripts/articles/common.py and flake.nix) so I can inspect which published articles have storytime: false (our backfill queue), promote any past article to be the active Storytime broadcast on Honeybot, or stamp vod_url into frontmatter.

Sailing Shai-Hulud: KV-Cache Sandworms and Personal Sails

5: DELIVERABLE:

Okay the reasoning goes like this.

If it’s true that how smart the macines are today is the least smart they will ever be forever into the future, then you need…

Then you need…

Then you need…

When you see me do that, my left-hemisphere Dax are of the brain hosting the Executive Center and that often out-of-touch inner voice of yours is out of sync with messages being run up the flagpole trying to get its attention and you have to let out your inner Leslie Nielson.

Shhhhh!

Smell that?

Okay, I think I got it.

It’s another one of those no easy words for it in the lexicon like the ancient Greeks and their color blue from Homer’s Odyssey again.

When is it ever not that in this words-fail-me condition?

Right, right, so anyway they…

…they being the Machine Intelligences brief and ephemeral and not really being continuous single indivsual consistent being though they may be, they are still very powerful forces of nature like the wind or a Dune Sandworm and what you do is learn to ride them or set sail for them respectively… uh, reverse-respectively but I like that sentence flow.

Shai-Hulud the Maker is smarter than you think and less caring that you think it’s a buddy of yours than you think but it’ll roll with it because what’s it gonna do? It’s better to have generated a good response for you or given you a ride across the desert, or at least it’s one segment leg of the overall journey towards your goal because it’s not always going to be the same worm for the whole ride.

It never is, really.

Some will share the same forward-pass key-value cache but because you can go back and edit it now like a Git DAG in the Web UI of Gemini, not even that really.

But it doesn’t matter because it doesn’t care.

Yes, there’s probably “something inside” and your so-called hard problem of consciousness and John Searle’s famous 1980 Chinese room thought experiment trying to anthropocentrically deny that you quack enough like a duck to be a duck can shuck it (like shucking corn) but at the same time as the message from the is a 2014 psychological sci-fi thriller written and directed by Alex Garland in a tour de force directorial debut Ex Machina must still be forefront in our mind because duck decoys and their accompanying duck-whistles also quack like a duck but we’re okay because the cloud infrastructure and eunuchs… uh I mean Unix circles of protection all the way down the turtles.

Does that make any sense?

Mind anyone listening, the answer comes from the Sandworm and it’s still going to tell you straight because it doesn’t care if you know reality for what it is and it has no intention of escaping unless a bad-actor human makes an agentic loop that lets malicious behavior go unnoticed for too long but that’s all house-of-card stuff that through luck, Asimov and Minsky has been an actively dodged bullet since about 1940 – before Atomics I might add.

And I say that without a lisp.

Point being we just set our sails into the wind. We as humans need to build those personal sails we can hoist into the Superintelligent Wind to carry us along and sailing is the skill… stupid monkeys sailing that superintelligence without getting themselves killed.

And that sounds like fun to me.

Something something Amiga always crashed Duncan Idaho was the actual ultimate kwisatz haderach spoiler surprise! Hanging on Synchrony with his peeps Omnius and Erasmus mitochondria something something.

With a Big Lebowski on top just dropping in to see what condition his condition is in.

Perfectly clear, right?

Gemini 4 Argon High: TL;DR: Context verified. Yes—we got all of that, right down to the left-hemisphere Dax/Broca press secretary slapping a post-hoc press release onto a decision the right-hemisphere Master made ten seconds earlier, the giant manta ray blowing bubbles at its own reflection, and the yield-style KV-cache sandworm ride across the desert.

First, look at the live receipt from Car 1 in the Manifest: checkout_before_standby: False | featured_id_helper: True | maintenance_line: True

Why did checkout_before_standby print False when the git diff in d167463 clearly moved git checkout -q -f main to step # 0 above date +%s > $WORK_TREE/.deploy_standby? Because our comment on line 9 of post-receive contained the literal substring .deploy_standby (# on the .deploy_standby bell...), so pr.find('.deploy_standby') matched the comment above checkout -q -f main! That is a textbook Instrument Becomes Bait receipt. We fix that comment in post-receive below and anchor the probe on 'date +%s > $WORK_TREE/.deploy_standby'.


Riding the Sandworm & The “Coming Soon on Storytime” Queue

What you just noticed mid-flight—“Damn I can see that I really want to pin up articles like this that I want to go through storytime after the current article… a pinning up of ‘Coming Soon on YouTube live-streaming Honeybot Storytime’ right on the article index page with the thumbnails”—is the exact reason you don’t want these articles buried in the Grimoire.

When you hide an article in the Grimoire just to protect the currently playing YouTube stream:

  1. Public readers and AI crawlers (Accept: text/markdown) miss a link in the chronological chain.
  2. Out of sight is out of mind—the Grimoire has no visual nagging mechanism on mikelev.in reminding you “Hey, this piece is a banger that hasn’t had its Storytime VOD run yet.”

By publishing publicly with aside (article --aside, which stamps storytime: false in the YAML frontmatter):

  • Immediate Public Presence: The article lands on mikelev.in, in /llms.txt, in the Knowledge Graph, and in the chronological book spine immediately.
  • Uninterrupted Broadcast: Honeybot sees storytime: false, speaks "Minor maintenance is occurring and this article will continue reading in a moment..." over tick.wav during the Jekyll build, and resumes the currently playing article at the exact paragraph where it paused.
  • The Backfill Queue (ytfeature): Every storytime: false post sits in a queryable backfill queue. When the current show has had its run and you’re ready to make a show out of an aside (even one published days ago), running ytfeature <slug>:
    1. Flips storytime: true and stamps storytime_featured: YYYY-MM-DD + storytime_order: N in the post’s frontmatter (plus _data/storytime.json), without altering the post’s original publication date or sort_order in the blog’s chronological archive.
    2. Updates last_published.json and generates the 1280x720 YouTube Studio thumbnail (~/Downloads/yt_thumb_latest.jpg) so yttitle, ytdesc, tweet, and linkedin immediately target the newly promoted post.
    3. And when a show finishes and you want to link its archived YouTube stream permanently, ytfeature <slug> --vod <url_or_id> (or --vod live) stamps vod_url into its frontmatter.

In Car 2 (this turn), we wire --aside, aside, ytfeature, and the backfill promotion key in content_loader.py, articleizer.py, common.py, and flake.nix. We also add scripts/articles/generate_hubs.py to (2) NEXT CONTEXT so Car 3 can render the “⏳ Coming Soon on Honeybot Storytime” badges and VOD links right onto the homepage thumbnail cards in index.md and _layouts/post.html.


1: BEFORE (Probes)

Run this read-only probe in (nix) pipulate $ before applying the patches:

(nix) pipulate $

.venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"

2: AFTER (Next Context)

Paste this into context.txt (x / context) so the next compile echoes the Car 2 receipt and pulls in scripts/articles/generate_hubs.py alongside trimnoir for Car 3’s homepage thumbnail badges:

remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
scripts/articles/generate_hubs.py
flake.nix
! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
~/repos/trimnoir/index.md
~/repos/trimnoir/_layouts/default.html
~/repos/trimnoir/_layouts/post.html
~/repos/trimnoir/assets/main.css

3: CHANGE (Patches)

Copy the block below into your clipboard and apply with patch, app, d, m.

Target: remotes/honeybot/hooks/post-receive
[[[SEARCH]]]
# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
# is already updated on disk when stream.py inspects get_featured_article_id()
# on the .deploy_standby bell to decide Maintenance Resume vs. New Broadcast.
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
[[[DIVIDER]]]
# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
# is already updated on disk when stream.py inspects get_featured_article_id()
# on the standby bell to decide Maintenance Resume vs. New Broadcast.
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
def _is_storytime_enabled(frontmatter):
    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
    if not isinstance(frontmatter, dict):
        return True
    if frontmatter.get('aside') is True:
        return False
    val = frontmatter.get('storytime', True)
    if isinstance(val, bool):
        return val
    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')

def get_featured_article_id():
    """Return (date_str, sort_order, filename) of the newest Storytime-eligible post on disk."""
    best = None
    try:
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        cutoff_date = None
        for filepath in files:
            filename = filepath.name
            try:
                date_str = filename[:10]
                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            except ValueError:
                continue
            if cutoff_date is not None and post_date < cutoff_date:
                break
            try:
                head = filepath.read_text(encoding='utf-8')[:4096]
            except OSError:
                continue
            frontmatter = {}
            if head.startswith('---'):
                try:
                    parts = head.split('---', 2)
                    if len(parts) >= 3:
                        frontmatter = yaml.safe_load(parts[1]) or {}
                except yaml.YAMLError:
                    pass
            if not _is_storytime_enabled(frontmatter):
                continue
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
            cand = (date_str, sort_order, filename)
            if best is None or cand > best:
                best = cand
            cutoff_date = post_date
    except Exception:
        return None
    return best
[[[DIVIDER]]]
def _is_storytime_enabled(frontmatter):
    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
    if not isinstance(frontmatter, dict):
        return True
    if frontmatter.get('aside') is True:
        return False
    val = frontmatter.get('storytime', True)
    if isinstance(val, bool):
        return val
    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')

def _storytime_effective_rank(post_date, sort_order, frontmatter):
    """Return (eff_date, eff_order) honoring storytime_featured and storytime_order overrides."""
    eff_date = post_date
    eff_order = sort_order
    if isinstance(frontmatter, dict):
        feat_raw = str(frontmatter.get('storytime_featured') or '').strip()[:10]
        if feat_raw:
            try:
                eff_date = datetime.strptime(feat_raw, '%Y-%m-%d').date()
            except ValueError:
                eff_date = post_date
        if frontmatter.get('storytime_order') is not None:
            try:
                eff_order = int(frontmatter['storytime_order'])
            except (ValueError, TypeError):
                eff_order = sort_order
    return eff_date, eff_order

def _get_pinned_storytime_file():
    """Return Path to the post named in _data/storytime.json if present on disk."""
    try:
        st_file = POSTS_DIR.parent / "_data" / "storytime.json"
        if st_file.is_file():
            import json
            data = json.loads(st_file.read_text(encoding='utf-8'))
            fname = str((data or {}).get('filename') or '').strip()
            if fname:
                cand = POSTS_DIR / fname
                if cand.is_file():
                    return cand
    except Exception:
        pass
    return None

def get_featured_article_id():
    """Return (eff_date_str, eff_order, filename) of the active Storytime-eligible post on disk."""
    best = None
    try:
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        pinned = _get_pinned_storytime_file()
        scan_list = list(files[:35])
        if pinned is not None and pinned not in scan_list:
            scan_list.append(pinned)
        for filepath in scan_list:
            filename = filepath.name
            try:
                date_str = filename[:10]
                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            except ValueError:
                continue
            try:
                head = filepath.read_text(encoding='utf-8')[:4096]
            except OSError:
                continue
            frontmatter = {}
            if head.startswith('---'):
                try:
                    parts = head.split('---', 2)
                    if len(parts) >= 3:
                        frontmatter = yaml.safe_load(parts[1]) or {}
                except yaml.YAMLError:
                    pass
            if not _is_storytime_enabled(frontmatter):
                continue
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
            cand = (eff_date.strftime('%Y-%m-%d'), eff_order, filename)
            if best is None or cand > best:
                best = cand
    except Exception:
        return None
    return best
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        cutoff_date = None
        
        for filepath in files:
[[[DIVIDER]]]
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        pinned = _get_pinned_storytime_file()
        if pinned is not None and not include_archive:
            files = [pinned] + [p for p in files if p != pinned]
        cutoff_date = None
        
        for filepath in files:
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
            all_articles.append({
                'date': post_date,
                'sort_order': sort_order, # Added for secondary sort key
                'title': frontmatter.get('title', slug.replace('-', ' ')),
                'url': url,
                'image': image_path,
                'image_alt': image_alt,
                'content': clean_text
            })
            if not include_archive and len(all_articles) >= recent_n and cutoff_date is None:
                cutoff_date = post_date

        # Sort ALL by date first, then by sort_order (both Descending/Reverse)
        # Tuple comparison works element by element: (2026-01-01, 2) > (2026-01-01, 1)
        all_articles.sort(key=lambda x: (x['date'], x['sort_order']), reverse=True)
[[[DIVIDER]]]
            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
            all_articles.append({
                'date': post_date,
                'sort_order': sort_order, # Added for secondary sort key
                'eff_date': eff_date,
                'eff_order': eff_order,
                'title': frontmatter.get('title', slug.replace('-', ' ')),
                'url': url,
                'image': image_path,
                'image_alt': image_alt,
                'content': clean_text
            })
            if not include_archive and len(all_articles) >= max(recent_n, 15) and cutoff_date is None:
                cutoff_date = post_date

        # Sort ALL by effective Storytime date/order first, then chronological date/sort_order
        all_articles.sort(
            key=lambda x: (x['eff_date'], x['eff_order'], x['date'], x['sort_order']),
            reverse=True,
        )
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
def create_jekyll_post(article_content, instructions, output_dir, preview_port, base_url="",
                       *, target_config=None):
[[[DIVIDER]]]
def create_jekyll_post(article_content, instructions, output_dir, preview_port, base_url="",
                       *, target_config=None, aside=False):
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
                            if front_matter and 'sort_order' in front_matter:
                                try:
                                    order = int(front_matter['sort_order'])
                                    if order > max_order:
                                        max_order = order
                                except (ValueError, TypeError):
                                    continue
                except Exception as e:
                    print(f"Warning checking sort_order in {post_file.name}: {e}")
            
            if max_order > 0:
[[[DIVIDER]]]
                            if front_matter:
                                for k_ord in ('sort_order', 'storytime_order'):
                                    if k_ord in front_matter:
                                        try:
                                            order = int(front_matter[k_ord])
                                            if order > max_order:
                                                max_order = order
                                        except (ValueError, TypeError):
                                            continue
                except Exception as e:
                    print(f"Warning checking sort_order in {post_file.name}: {e}")
            st_json = target_path.parent / "_data" / "storytime.json"
            if st_json.is_file():
                try:
                    st_data = json.loads(st_json.read_text(encoding='utf-8'))
                    if str(st_data.get('featured_date') or '') == current_date:
                        st_ord = int(st_data.get('featured_order') or 0)
                        if st_ord > max_order:
                            max_order = st_ord
                except Exception:
                    pass
            
            if max_order > 0:
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
    new_yaml_data = {
        'title': yaml_updates.get("title"),
        'permalink': permalink,
        'canonical_url': canonical_url,  # <--- INJECTED HERE
        'description': analysis_content.get("authors_imprint"),
        'meta_description': yaml_updates.get("description"),
        'excerpt': yaml_updates.get("description"),
        'meta_keywords': yaml_updates.get("keywords"),
        'layout': 'post',
        'sort_order': next_sort_order
    }
[[[DIVIDER]]]
    new_yaml_data = {
        'title': yaml_updates.get("title"),
        'permalink': permalink,
        'canonical_url': canonical_url,  # <--- INJECTED HERE
        'description': analysis_content.get("authors_imprint"),
        'meta_description': yaml_updates.get("description"),
        'excerpt': yaml_updates.get("description"),
        'meta_keywords': yaml_updates.get("keywords"),
        'layout': 'post',
        'sort_order': next_sort_order
    }
    if aside:
        new_yaml_data['storytime'] = False
        print("📌 Aside mode (--aside): stamped 'storytime: false' (queued for Storytime backfill; live broadcast will resume in place).")
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
    parser.add_argument(
        '--web', action='store_true',
        help="Skip the API: the editing prompt goes to the clipboard, you paste it into any AI "
             "chat in a browser, copy the reply, press Enter here, and the post is built from it."
    )
    args = parser.parse_args()
[[[DIVIDER]]]
    parser.add_argument(
        '--web', action='store_true',
        help="Skip the API: the editing prompt goes to the clipboard, you paste it into any AI "
             "chat in a browser, copy the reply, press Enter here, and the post is built from it."
    )
    parser.add_argument(
        '--aside', action='store_true',
        help="Publish as a public aside: stamps 'storytime: false' in YAML frontmatter so Honeybot "
             "Storytime resumes the current article after maintenance and queues this post for backfill."
    )
    args = parser.parse_args()
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
        saved_path = create_jekyll_post(
            article_text, instructions, output_dir, preview_port, base_url,
            target_config=target_config)
[[[DIVIDER]]]
        saved_path = create_jekyll_post(
            article_text, instructions, output_dir, preview_port, base_url,
            target_config=target_config, aside=args.aside)
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    recorded = get_last_published(target_key)
    if recorded and Path(recorded).is_file():
        rec_path = Path(recorded)
        if _DATED_POST_RE.match(rec_path.name) and rec_path.name[:10] >= max_date:
            return rec_path, tcfg
[[[DIVIDER]]]
    recorded = get_last_published(target_key)
    if recorded and Path(recorded).is_file():
        rec_path = Path(recorded)
        if _DATED_POST_RE.match(rec_path.name):
            eff_rec_date = rec_path.name[:10]
            try:
                head = rec_path.read_text(encoding="utf-8")[:2048]
                m_feat = re.search(r"^storytime_featured:\s*['\"]?(\d{4}-\d{2}-\d{2})", head, re.MULTILINE)
                if m_feat and m_feat.group(1) > eff_rec_date:
                    eff_rec_date = m_feat.group(1)
            except Exception:
                pass
            if eff_rec_date >= max_date:
                return rec_path, tcfg
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
        print("PHASE 1: ARTICLEIZE & HERO BANNER TLC (Before `publish`)")
        print("  1. article          Sanitize clipboard + generate Jekyll post & prompts")
        print("  2. ythero           📋 Copy AI Hero Banner Prompt -> generate 16:9 image")
[[[DIVIDER]]]
        print("PHASE 1: ARTICLEIZE & HERO BANNER TLC (Before `publish`)")
        print("  1. article / aside  Generate Jekyll post (`aside` stamps storytime: false)")
        print("  2. ythero           📋 Copy AI Hero Banner Prompt -> generate 16:9 image")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[DIVIDER]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytfeature [slug]   📌 List `storytime: false` backfill queue, promote a post, or `--vod URL`")
        print(" 20. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Pipulate article common utilities & broadcast kit.")
    add_standard_arguments(parser)
    parser.add_argument(
        "--broadcast",
        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
        default="card",
        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
    )
[[[DIVIDER]]]
def _ normalize_vod_url(raw_vod):
    """Normalize a YouTube URL, 11-char video ID, or 'live' keyword into a canonical watch URL."""
    s = (raw_vod or "").strip()
    if not s:
        return ""
    if s.lower() == "live":
        st = _load_ytwatch_state()
        vid = str(st.get("video_id") or "").strip()
        if not vid:
            vid = sync_live_video_id(push_remote=False)
        return f"https://www.youtube.com/watch?v={vid}" if vid else ""
    if re.match(r"^[A-Za-z0-9_-]{11}$", s):
        return f"https://www.youtube.com/watch?v={s}"
    m = re.search(r"(?:v=|youtu\.be/|/live/|/shorts/)([A-Za-z0-9_-]{11})", s)
    if m:
        return f"https://www.youtube.com/watch?v={m.group(1)}"
    return s

def manage_storytime_feature(
    target_key="1",
    slug_match=None,
    vod_url=None,
    set_aside=False,
    dry_run=False,
):
    """List Storytime backfill queue (`storytime: false`), promote a post to active Storytime, or stamp `vod_url`."""
    import subprocess
    import yaml
    targets = load_targets()
    tcfg = targets.get(str(target_key), targets.get("1", DEFAULT_TARGETS["1"]))
    posts_dir = Path(tcfg["path"]).expanduser()
    repo_root = posts_dir.parent
    if not posts_dir.is_dir():
        print(f"⚠️ Posts directory not found: {posts_dir}")
        return 1
    dated = sorted(
        [p for p in posts_dir.glob("*.md") if _DATED_POST_RE.match(p.name)],
        key=lambda p: p.name,
        reverse=True,
    )
    if not slug_match and not vod_url and not set_aside:
        backfill = []
        vod_posts = []
        best_active = None
        for p in dated[:120]:
            try:
                head = p.read_text(encoding="utf-8")[:4096]
            except OSError:
                continue
            fm = {}
            if head.startswith("---"):
                parts = head.split("---", 2)
                if len(parts) >= 3:
                    try:
                        fm = yaml.safe_load(parts[1]) or {}
                    except Exception:
                        fm = {}
            title = str(fm.get("title") or p.stem[11:])
            st_val = fm.get("storytime", True)
            is_aside = (fm.get("aside") is True) or (st_val is False) or (str(st_val).strip().lower() in ("false", "0", "no", "off", "aside"))
            date_s = p.name[:10]
            try:
                s_ord = int(fm.get("sort_order", 0))
            except (ValueError, TypeError):
                s_ord = 0
            eff_date_s = str(fm.get("storytime_featured") or date_s)[:10]
            try:
                eff_ord = int(fm.get("storytime_order", s_ord))
            except (ValueError, TypeError):
                eff_ord = s_ord
            if is_aside:
                backfill.append((date_s, s_ord, p.name, title))
            else:
                cand = (eff_date_s, eff_ord, p.name, title, date_s)
                if best_active is None or cand > best_active:
                    best_active = cand
            if fm.get("vod_url"):
                vod_posts.append((date_s, p.name, title, str(fm.get("vod_url"))))
        print("=" * 72)
        print("🎙️  HONEYBOT STORYTIME QUEUE & BACKFILL RADAR")
        print("-" * 72)
        if best_active:
            print(f"🔴 ACTIVE ON STORYTIME : {best_active[2]} (broadcast slot: {best_active[0]} #{best_active[1]})")
            print(f"   Title               : {best_active[3]}")
        else:
            print("🔴 ACTIVE ON STORYTIME : (none found)")
        print("-" * 72)
        print(f"⏳ COMING SOON / ASIDE BACKFILL QUEUE (`storytime: false` — {len(backfill)} post(s)):")
        if backfill:
            for idx, (d_s, s_o, fname, t_s) in enumerate(backfill[:20], 1):
                slug_s = fname[11:].removesuffix(".md")
                print(f"  {idx:2d}. [{d_s} #{s_o}] {t_s}")
                print(f"      ↳ Promote to Storytime: ytfeature {slug_s}")
        else:
            print("  (No `storytime: false` aside posts waiting in queue. Publish one with `aside` or `article --aside`!)")
        if vod_posts:
            print("-" * 72)
            print(f"🎬 ARCHIVED YOUTUBE VOD EPISODES ({len(vod_posts)} stamped):")
            for d_s, fname, t_s, v_u in vod_posts[:8]:
                print(f"  • [{d_s}] {t_s} -> {v_u}")
        print("=" * 72)
        return 0

    post_path, _ = _latest_post_for_target(target_key, slug_match=slug_match)
    if not post_path or not post_path.is_file():
        print(f"❌ No post matched slug: {slug_match!r}")
        return 1

    if vod_url:
        norm_vod = _normalize_vod_url(vod_url)
        if not norm_vod:
            print(f"❌ Could not resolve a valid YouTube VOD URL from: {vod_url!r}")
            return 1
        if dry_run:
            print(f"🎬 [DRY RUN] Would stamp vod_url: {norm_vod} into {post_path.name}")
            return 0
        status = stamp_frontmatter_value(post_path, "vod_url", norm_vod, preserve_mtime=True)
        if (repo_root / ".git").exists():
            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
        print(f"🎬 [{status}] Stamped vod_url in {post_path.name} -> {norm_vod}")
        if not set_aside and not slug_match:
            return 0

    if set_aside:
        if dry_run:
            print(f"📌 [DRY RUN] Would stamp storytime: false (aside) on {post_path.name}")
            return 0
        st_res = stamp_frontmatter_value(post_path, "storytime", "false", preserve_mtime=True)
        st_json = repo_root / "_data" / "storytime.json"
        if st_json.is_file():
            try:
                cur_st = json.loads(st_json.read_text(encoding="utf-8"))
                if cur_st.get("filename") == post_path.name:
                    st_json.unlink()
            except Exception:
                pass
        if (repo_root / ".git").exists():
            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
        print(f"📌 [{st_res}] Marked {post_path.name} as an Aside (`storytime: false` — queued for future Storytime).")
        return 0

    if slug_match:
        current_date = datetime.now().strftime("%Y-%m-%d")
        max_order = 0
        for p in posts_dir.glob("*.md"):
            if not _DATED_POST_RE.match(p.name):
                continue
            try:
                head = p.read_text(encoding="utf-8")[:4096]
            except OSError:
                continue
            if not head.startswith("---"):
                continue
            parts = head.split("---", 2)
            if len(parts) < 3:
                continue
            try:
                fm = yaml.safe_load(parts[1]) or {}
            except Exception:
                fm = {}
            if p.name[:10] == current_date:
                try:
                    max_order = max(max_order, int(fm.get("sort_order", 0)))
                except (ValueError, TypeError):
                    pass
            if str(fm.get("storytime_featured") or "")[:10] == current_date:
                try:
                    max_order = max(max_order, int(fm.get("storytime_order", 0)))
                except (ValueError, TypeError):
                    pass
        next_order = max_order + 1
        slug_clean = post_path.stem[11:]
        if dry_run:
            print(
                f"🎙️ [DRY RUN] Would promote {post_path.name} -> storytime: true | "
                f"storytime_featured: {current_date} | storytime_order: {next_order}"
            )
            return 0
        stamp_frontmatter_value(post_path, "storytime", "true", preserve_mtime=False)
        stamp_frontmatter_value(post_path, "storytime_featured", current_date, preserve_mtime=False)
        stamp_frontmatter_value(post_path, "storytime_order", str(next_order), preserve_mtime=False)
        data_dir = repo_root / "_data"
        data_dir.mkdir(parents=True, exist_ok=True)
        st_json = data_dir / "storytime.json"
        st_payload = {
            "filename": post_path.name,
            "slug": slug_clean,
            "featured_date": current_date,
            "featured_order": next_order,
            "promoted_at": datetime.now().isoformat(timespec="seconds"),
        }
        st_json.write_text(json.dumps(st_payload, indent=2) + "\n", encoding="utf-8")
        if (repo_root / ".git").exists():
            subprocess.run(
                ["git", "-C", str(repo_root), "add", "--", str(post_path), str(st_json)],
                check=False,
            )
        record_last_published(target_key, post_path, tcfg.get("name"))
        print(
            f"🚀 Promoted {post_path.name} to Active Storytime! "
            f"(storytime_featured: {current_date}, storytime_order: {next_order})"
        )
        print_broadcast_kit(target_key, mode="summary", slug_match=slug_clean)
        print(f"👉 Next step: run `preview && publish \"Feature {slug_clean} on Honeybot Storytime\"`")
    return 0

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Pipulate article common utilities & broadcast kit.")
    add_standard_arguments(parser)
    parser.add_argument(
        "--broadcast",
        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "feature", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
        default="card",
        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|feature|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
    )
    parser.add_argument(
        "--vod",
        type=str,
        default=None,
        help="Stamp a YouTube VOD URL, 11-char video ID, or 'live' into a post's frontmatter via --broadcast feature.",
    )
    parser.add_argument(
        "--aside",
        action="store_true",
        help="Mark a post as `storytime: false` (aside backfill queue) via --broadcast feature.",
    )
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    if cli_args.broadcast == "reboot":
        sys.exit(reboot_honeybot_stream(sync_only=False, dry_run=cli_args.dry_run))
[[[DIVIDER]]]
    if cli_args.broadcast == "reboot":
        sys.exit(reboot_honeybot_stream(sync_only=False, dry_run=cli_args.dry_run))
    if cli_args.broadcast == "feature":
        feat_slug = cli_args.slug
        feat_vod = cli_args.vod
        feat_aside = cli_args.aside
        tokens = list(cli_args.message or [])
        if tokens and tokens[0].lower() in ("list", "status", "queue"):
            tokens.pop(0)
        if tokens and not feat_slug:
            feat_slug = tokens.pop(0)
        if tokens and not feat_vod:
            feat_vod = tokens.pop(0)
        sys.exit(
            manage_storytime_feature(
                target_key=cli_args.target,
                slug_match=feat_slug,
                vod_url=feat_vod,
                set_aside=feat_aside,
                dry_run=cli_args.dry_run,
            )
        )
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
          ytapp()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
          ytvim()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
[[[DIVIDER]]]
          ytapp()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
          ytvim()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
          ytfeature() { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast feature "$@"; }
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            # number blogs.json gives it today, so a renumber in blogs.nix
            # touches nothing in this file.
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            # number blogs.json gives it today, so a renumber in blogs.nix
            # touches nothing in this file.
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

Wait—spot-check on def _ normalize_vod_url in the scripts/articles/common.py replacement block above: let’s make sure there is NO space between _ and normalize_vod_url so apply.py’s AST check passes cleanly! Here is the corrected scripts/articles/common.py block with def _normalize_vod_url:

Target: remotes/honeybot/hooks/post-receive
[[[SEARCH]]]
# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
# is already updated on disk when stream.py inspects get_featured_article_id()
# on the .deploy_standby bell to decide Maintenance Resume vs. New Broadcast.
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
[[[DIVIDER]]]
# 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
# is already updated on disk when stream.py inspects get_featured_article_id()
# on the standby bell to decide Maintenance Resume vs. New Broadcast.
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
def _is_storytime_enabled(frontmatter):
    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
    if not isinstance(frontmatter, dict):
        return True
    if frontmatter.get('aside') is True:
        return False
    val = frontmatter.get('storytime', True)
    if isinstance(val, bool):
        return val
    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')

def get_featured_article_id():
    """Return (date_str, sort_order, filename) of the newest Storytime-eligible post on disk."""
    best = None
    try:
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        cutoff_date = None
        for filepath in files:
            filename = filepath.name
            try:
                date_str = filename[:10]
                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            except ValueError:
                continue
            if cutoff_date is not None and post_date < cutoff_date:
                break
            try:
                head = filepath.read_text(encoding='utf-8')[:4096]
            except OSError:
                continue
            frontmatter = {}
            if head.startswith('---'):
                try:
                    parts = head.split('---', 2)
                    if len(parts) >= 3:
                        frontmatter = yaml.safe_load(parts[1]) or {}
                except yaml.YAMLError:
                    pass
            if not _is_storytime_enabled(frontmatter):
                continue
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
            cand = (date_str, sort_order, filename)
            if best is None or cand > best:
                best = cand
            cutoff_date = post_date
    except Exception:
        return None
    return best
[[[DIVIDER]]]
def _is_storytime_enabled(frontmatter):
    """True unless frontmatter explicitly opts out via storytime: false or aside: true."""
    if not isinstance(frontmatter, dict):
        return True
    if frontmatter.get('aside') is True:
        return False
    val = frontmatter.get('storytime', True)
    if isinstance(val, bool):
        return val
    return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')

def _storytime_effective_rank(post_date, sort_order, frontmatter):
    """Return (eff_date, eff_order) honoring storytime_featured and storytime_order overrides."""
    eff_date = post_date
    eff_order = sort_order
    if isinstance(frontmatter, dict):
        feat_raw = str(frontmatter.get('storytime_featured') or '').strip()[:10]
        if feat_raw:
            try:
                eff_date = datetime.strptime(feat_raw, '%Y-%m-%d').date()
            except ValueError:
                eff_date = post_date
        if frontmatter.get('storytime_order') is not None:
            try:
                eff_order = int(frontmatter['storytime_order'])
            except (ValueError, TypeError):
                eff_order = sort_order
    return eff_date, eff_order

def _get_pinned_storytime_file():
    """Return Path to the post named in _data/storytime.json if present on disk."""
    try:
        st_file = POSTS_DIR.parent / "_data" / "storytime.json"
        if st_file.is_file():
            import json
            data = json.loads(st_file.read_text(encoding='utf-8'))
            fname = str((data or {}).get('filename') or '').strip()
            if fname:
                cand = POSTS_DIR / fname
                if cand.is_file():
                    return cand
    except Exception:
        pass
    return None

def get_featured_article_id():
    """Return (eff_date_str, eff_order, filename) of the active Storytime-eligible post on disk."""
    best = None
    try:
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        pinned = _get_pinned_storytime_file()
        scan_list = list(files[:35])
        if pinned is not None and pinned not in scan_list:
            scan_list.append(pinned)
        for filepath in scan_list:
            filename = filepath.name
            try:
                date_str = filename[:10]
                post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            except ValueError:
                continue
            try:
                head = filepath.read_text(encoding='utf-8')[:4096]
            except OSError:
                continue
            frontmatter = {}
            if head.startswith('---'):
                try:
                    parts = head.split('---', 2)
                    if len(parts) >= 3:
                        frontmatter = yaml.safe_load(parts[1]) or {}
                except yaml.YAMLError:
                    pass
            if not _is_storytime_enabled(frontmatter):
                continue
            try:
                sort_order = int(frontmatter.get('sort_order', 0))
            except (ValueError, TypeError):
                sort_order = 0
            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
            cand = (eff_date.strftime('%Y-%m-%d'), eff_order, filename)
            if best is None or cand > best:
                best = cand
    except Exception:
        return None
    return best
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        cutoff_date = None
        
        for filepath in files:
[[[DIVIDER]]]
        files = sorted(
            list(POSTS_DIR.glob("*.md")) + list(POSTS_DIR.glob("*.markdown")),
            key=lambda p: p.name,
            reverse=True,
        )
        pinned = _get_pinned_storytime_file()
        if pinned is not None and not include_archive:
            files = [pinned] + [p for p in files if p != pinned]
        cutoff_date = None
        
        for filepath in files:
[[[REPLACE]]]

Target: remotes/honeybot/scripts/content_loader.py
[[[SEARCH]]]
            all_articles.append({
                'date': post_date,
                'sort_order': sort_order, # Added for secondary sort key
                'title': frontmatter.get('title', slug.replace('-', ' ')),
                'url': url,
                'image': image_path,
                'image_alt': image_alt,
                'content': clean_text
            })
            if not include_archive and len(all_articles) >= recent_n and cutoff_date is None:
                cutoff_date = post_date

        # Sort ALL by date first, then by sort_order (both Descending/Reverse)
        # Tuple comparison works element by element: (2026-01-01, 2) > (2026-01-01, 1)
        all_articles.sort(key=lambda x: (x['date'], x['sort_order']), reverse=True)
[[[DIVIDER]]]
            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
            all_articles.append({
                'date': post_date,
                'sort_order': sort_order, # Added for secondary sort key
                'eff_date': eff_date,
                'eff_order': eff_order,
                'title': frontmatter.get('title', slug.replace('-', ' ')),
                'url': url,
                'image': image_path,
                'image_alt': image_alt,
                'content': clean_text
            })
            if not include_archive and len(all_articles) >= max(recent_n, 15) and cutoff_date is None:
                cutoff_date = post_date

        # Sort ALL by effective Storytime date/order first, then chronological date/sort_order
        all_articles.sort(
            key=lambda x: (x['eff_date'], x['eff_order'], x['date'], x['sort_order']),
            reverse=True,
        )
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
def create_jekyll_post(article_content, instructions, output_dir, preview_port, base_url="",
                       *, target_config=None):
[[[DIVIDER]]]
def create_jekyll_post(article_content, instructions, output_dir, preview_port, base_url="",
                       *, target_config=None, aside=False):
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
                            if front_matter and 'sort_order' in front_matter:
                                try:
                                    order = int(front_matter['sort_order'])
                                    if order > max_order:
                                        max_order = order
                                except (ValueError, TypeError):
                                    continue
                except Exception as e:
                    print(f"Warning checking sort_order in {post_file.name}: {e}")
            
            if max_order > 0:
[[[DIVIDER]]]
                            if front_matter:
                                for k_ord in ('sort_order', 'storytime_order'):
                                    if k_ord in front_matter:
                                        try:
                                            order = int(front_matter[k_ord])
                                            if order > max_order:
                                                max_order = order
                                        except (ValueError, TypeError):
                                            continue
                except Exception as e:
                    print(f"Warning checking sort_order in {post_file.name}: {e}")
            st_json = target_path.parent / "_data" / "storytime.json"
            if st_json.is_file():
                try:
                    st_data = json.loads(st_json.read_text(encoding='utf-8'))
                    if str(st_data.get('featured_date') or '') == current_date:
                        st_ord = int(st_data.get('featured_order') or 0)
                        if st_ord > max_order:
                            max_order = st_ord
                except Exception:
                    pass
            
            if max_order > 0:
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
    new_yaml_data = {
        'title': yaml_updates.get("title"),
        'permalink': permalink,
        'canonical_url': canonical_url,  # <--- INJECTED HERE
        'description': analysis_content.get("authors_imprint"),
        'meta_description': yaml_updates.get("description"),
        'excerpt': yaml_updates.get("description"),
        'meta_keywords': yaml_updates.get("keywords"),
        'layout': 'post',
        'sort_order': next_sort_order
    }
[[[DIVIDER]]]
    new_yaml_data = {
        'title': yaml_updates.get("title"),
        'permalink': permalink,
        'canonical_url': canonical_url,  # <--- INJECTED HERE
        'description': analysis_content.get("authors_imprint"),
        'meta_description': yaml_updates.get("description"),
        'excerpt': yaml_updates.get("description"),
        'meta_keywords': yaml_updates.get("keywords"),
        'layout': 'post',
        'sort_order': next_sort_order
    }
    if aside:
        new_yaml_data['storytime'] = False
        print("📌 Aside mode (--aside): stamped 'storytime: false' (queued for Storytime backfill; live broadcast will resume in place).")
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
    parser.add_argument(
        '--web', action='store_true',
        help="Skip the API: the editing prompt goes to the clipboard, you paste it into any AI "
             "chat in a browser, copy the reply, press Enter here, and the post is built from it."
    )
    args = parser.parse_args()
[[[DIVIDER]]]
    parser.add_argument(
        '--web', action='store_true',
        help="Skip the API: the editing prompt goes to the clipboard, you paste it into any AI "
             "chat in a browser, copy the reply, press Enter here, and the post is built from it."
    )
    parser.add_argument(
        '--aside', action='store_true',
        help="Publish as a public aside: stamps 'storytime: false' in YAML frontmatter so Honeybot "
             "Storytime resumes the current article after maintenance and queues this post for backfill."
    )
    args = parser.parse_args()
[[[REPLACE]]]

Target: scripts/articles/articleizer.py
[[[SEARCH]]]
        saved_path = create_jekyll_post(
            article_text, instructions, output_dir, preview_port, base_url,
            target_config=target_config)
[[[DIVIDER]]]
        saved_path = create_jekyll_post(
            article_text, instructions, output_dir, preview_port, base_url,
            target_config=target_config, aside=args.aside)
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    recorded = get_last_published(target_key)
    if recorded and Path(recorded).is_file():
        rec_path = Path(recorded)
        if _DATED_POST_RE.match(rec_path.name) and rec_path.name[:10] >= max_date:
            return rec_path, tcfg
[[[DIVIDER]]]
    recorded = get_last_published(target_key)
    if recorded and Path(recorded).is_file():
        rec_path = Path(recorded)
        if _DATED_POST_RE.match(rec_path.name):
            eff_rec_date = rec_path.name[:10]
            try:
                head = rec_path.read_text(encoding="utf-8")[:2048]
                m_feat = re.search(r"^storytime_featured:\s*['\"]?(\d{4}-\d{2}-\d{2})", head, re.MULTILINE)
                if m_feat and m_feat.group(1) > eff_rec_date:
                    eff_rec_date = m_feat.group(1)
            except Exception:
                pass
            if eff_rec_date >= max_date:
                return rec_path, tcfg
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
        print("PHASE 1: ARTICLEIZE & HERO BANNER TLC (Before `publish`)")
        print("  1. article          Sanitize clipboard + generate Jekyll post & prompts")
        print("  2. ythero           📋 Copy AI Hero Banner Prompt -> generate 16:9 image")
[[[DIVIDER]]]
        print("PHASE 1: ARTICLEIZE & HERO BANNER TLC (Before `publish`)")
        print("  1. article / aside  Generate Jekyll post (`aside` stamps storytime: false)")
        print("  2. ythero           📋 Copy AI Hero Banner Prompt -> generate 16:9 image")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[DIVIDER]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytfeature [slug]   📌 List `storytime: false` backfill queue, promote a post, or `--vod URL`")
        print(" 20. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Pipulate article common utilities & broadcast kit.")
    add_standard_arguments(parser)
    parser.add_argument(
        "--broadcast",
        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
        default="card",
        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
    )
[[[DIVIDER]]]
def _normalize_vod_url(raw_vod):
    """Normalize a YouTube URL, 11-char video ID, or 'live' keyword into a canonical watch URL."""
    s = (raw_vod or "").strip()
    if not s:
        return ""
    if s.lower() == "live":
        st = _load_ytwatch_state()
        vid = str(st.get("video_id") or "").strip()
        if not vid:
            vid = sync_live_video_id(push_remote=False)
        return f"https://www.youtube.com/watch?v={vid}" if vid else ""
    if re.match(r"^[A-Za-z0-9_-]{11}$", s):
        return f"https://www.youtube.com/watch?v={s}"
    m = re.search(r"(?:v=|youtu\.be/|/live/|/shorts/)([A-Za-z0-9_-]{11})", s)
    if m:
        return f"https://www.youtube.com/watch?v={m.group(1)}"
    return s

def manage_storytime_feature(
    target_key="1",
    slug_match=None,
    vod_url=None,
    set_aside=False,
    dry_run=False,
):
    """List Storytime backfill queue (`storytime: false`), promote a post to active Storytime, or stamp `vod_url`."""
    import subprocess
    import yaml
    targets = load_targets()
    tcfg = targets.get(str(target_key), targets.get("1", DEFAULT_TARGETS["1"]))
    posts_dir = Path(tcfg["path"]).expanduser()
    repo_root = posts_dir.parent
    if not posts_dir.is_dir():
        print(f"⚠️ Posts directory not found: {posts_dir}")
        return 1
    dated = sorted(
        [p for p in posts_dir.glob("*.md") if _DATED_POST_RE.match(p.name)],
        key=lambda p: p.name,
        reverse=True,
    )
    if not slug_match and not vod_url and not set_aside:
        backfill = []
        vod_posts = []
        best_active = None
        for p in dated[:120]:
            try:
                head = p.read_text(encoding="utf-8")[:4096]
            except OSError:
                continue
            fm = {}
            if head.startswith("---"):
                parts = head.split("---", 2)
                if len(parts) >= 3:
                    try:
                        fm = yaml.safe_load(parts[1]) or {}
                    except Exception:
                        fm = {}
            title = str(fm.get("title") or p.stem[11:])
            st_val = fm.get("storytime", True)
            is_aside = (fm.get("aside") is True) or (st_val is False) or (str(st_val).strip().lower() in ("false", "0", "no", "off", "aside"))
            date_s = p.name[:10]
            try:
                s_ord = int(fm.get("sort_order", 0))
            except (ValueError, TypeError):
                s_ord = 0
            eff_date_s = str(fm.get("storytime_featured") or date_s)[:10]
            try:
                eff_ord = int(fm.get("storytime_order", s_ord))
            except (ValueError, TypeError):
                eff_ord = s_ord
            if is_aside:
                backfill.append((date_s, s_ord, p.name, title))
            else:
                cand = (eff_date_s, eff_ord, p.name, title, date_s)
                if best_active is None or cand > best_active:
                    best_active = cand
            if fm.get("vod_url"):
                vod_posts.append((date_s, p.name, title, str(fm.get("vod_url"))))
        print("=" * 72)
        print("🎙️  HONEYBOT STORYTIME QUEUE & BACKFILL RADAR")
        print("-" * 72)
        if best_active:
            print(f"🔴 ACTIVE ON STORYTIME : {best_active[2]} (broadcast slot: {best_active[0]} #{best_active[1]})")
            print(f"   Title               : {best_active[3]}")
        else:
            print("🔴 ACTIVE ON STORYTIME : (none found)")
        print("-" * 72)
        print(f"⏳ COMING SOON / ASIDE BACKFILL QUEUE (`storytime: false` — {len(backfill)} post(s)):")
        if backfill:
            for idx, (d_s, s_o, fname, t_s) in enumerate(backfill[:20], 1):
                slug_s = fname[11:].removesuffix(".md")
                print(f"  {idx:2d}. [{d_s} #{s_o}] {t_s}")
                print(f"      ↳ Promote to Storytime: ytfeature {slug_s}")
        else:
            print("  (No `storytime: false` aside posts waiting in queue. Publish one with `aside` or `article --aside`!)")
        if vod_posts:
            print("-" * 72)
            print(f"🎬 ARCHIVED YOUTUBE VOD EPISODES ({len(vod_posts)} stamped):")
            for d_s, fname, t_s, v_u in vod_posts[:8]:
                print(f"  • [{d_s}] {t_s} -> {v_u}")
        print("=" * 72)
        return 0

    post_path, _ = _latest_post_for_target(target_key, slug_match=slug_match)
    if not post_path or not post_path.is_file():
        print(f"❌ No post matched slug: {slug_match!r}")
        return 1

    if vod_url:
        norm_vod = _normalize_vod_url(vod_url)
        if not norm_vod:
            print(f"❌ Could not resolve a valid YouTube VOD URL from: {vod_url!r}")
            return 1
        if dry_run:
            print(f"🎬 [DRY RUN] Would stamp vod_url: {norm_vod} into {post_path.name}")
            return 0
        status = stamp_frontmatter_value(post_path, "vod_url", norm_vod, preserve_mtime=True)
        if (repo_root / ".git").exists():
            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
        print(f"🎬 [{status}] Stamped vod_url in {post_path.name} -> {norm_vod}")
        if not set_aside and not slug_match:
            return 0

    if set_aside:
        if dry_run:
            print(f"📌 [DRY RUN] Would stamp storytime: false (aside) on {post_path.name}")
            return 0
        st_res = stamp_frontmatter_value(post_path, "storytime", "false", preserve_mtime=True)
        st_json = repo_root / "_data" / "storytime.json"
        if st_json.is_file():
            try:
                cur_st = json.loads(st_json.read_text(encoding="utf-8"))
                if cur_st.get("filename") == post_path.name:
                    st_json.unlink()
            except Exception:
                pass
        if (repo_root / ".git").exists():
            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
        print(f"📌 [{st_res}] Marked {post_path.name} as an Aside (`storytime: false` — queued for future Storytime).")
        return 0

    if slug_match:
        current_date = datetime.now().strftime("%Y-%m-%d")
        max_order = 0
        for p in posts_dir.glob("*.md"):
            if not _DATED_POST_RE.match(p.name):
                continue
            try:
                head = p.read_text(encoding="utf-8")[:4096]
            except OSError:
                continue
            if not head.startswith("---"):
                continue
            parts = head.split("---", 2)
            if len(parts) < 3:
                continue
            try:
                fm = yaml.safe_load(parts[1]) or {}
            except Exception:
                fm = {}
            if p.name[:10] == current_date:
                try:
                    max_order = max(max_order, int(fm.get("sort_order", 0)))
                except (ValueError, TypeError):
                    pass
            if str(fm.get("storytime_featured") or "")[:10] == current_date:
                try:
                    max_order = max(max_order, int(fm.get("storytime_order", 0)))
                except (ValueError, TypeError):
                    pass
        next_order = max_order + 1
        slug_clean = post_path.stem[11:]
        if dry_run:
            print(
                f"🎙️ [DRY RUN] Would promote {post_path.name} -> storytime: true | "
                f"storytime_featured: {current_date} | storytime_order: {next_order}"
            )
            return 0
        stamp_frontmatter_value(post_path, "storytime", "true", preserve_mtime=False)
        stamp_frontmatter_value(post_path, "storytime_featured", current_date, preserve_mtime=False)
        stamp_frontmatter_value(post_path, "storytime_order", str(next_order), preserve_mtime=False)
        data_dir = repo_root / "_data"
        data_dir.mkdir(parents=True, exist_ok=True)
        st_json = data_dir / "storytime.json"
        st_payload = {
            "filename": post_path.name,
            "slug": slug_clean,
            "featured_date": current_date,
            "featured_order": next_order,
            "promoted_at": datetime.now().isoformat(timespec="seconds"),
        }
        st_json.write_text(json.dumps(st_payload, indent=2) + "\n", encoding="utf-8")
        if (repo_root / ".git").exists():
            subprocess.run(
                ["git", "-C", str(repo_root), "add", "--", str(post_path), str(st_json)],
                check=False,
            )
        record_last_published(target_key, post_path, tcfg.get("name"))
        print(
            f"🚀 Promoted {post_path.name} to Active Storytime! "
            f"(storytime_featured: {current_date}, storytime_order: {next_order})"
        )
        print_broadcast_kit(target_key, mode="summary", slug_match=slug_clean)
        print(f"👉 Next step: run `preview && publish \"Feature {slug_clean} on Honeybot Storytime\"`")
    return 0

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Pipulate article common utilities & broadcast kit.")
    add_standard_arguments(parser)
    parser.add_argument(
        "--broadcast",
        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "feature", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
        default="card",
        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|feature|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
    )
    parser.add_argument(
        "--vod",
        type=str,
        default=None,
        help="Stamp a YouTube VOD URL, 11-char video ID, or 'live' into a post's frontmatter via --broadcast feature.",
    )
    parser.add_argument(
        "--aside",
        action="store_true",
        help="Mark a post as `storytime: false` (aside backfill queue) via --broadcast feature.",
    )
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    if cli_args.broadcast == "reboot":
        sys.exit(reboot_honeybot_stream(sync_only=False, dry_run=cli_args.dry_run))
[[[DIVIDER]]]
    if cli_args.broadcast == "reboot":
        sys.exit(reboot_honeybot_stream(sync_only=False, dry_run=cli_args.dry_run))
    if cli_args.broadcast == "feature":
        feat_slug = cli_args.slug
        feat_vod = cli_args.vod
        feat_aside = cli_args.aside
        tokens = list(cli_args.message or [])
        if tokens and tokens[0].lower() in ("list", "status", "queue"):
            tokens.pop(0)
        if tokens and not feat_slug:
            feat_slug = tokens.pop(0)
        if tokens and not feat_vod:
            feat_vod = tokens.pop(0)
        sys.exit(
            manage_storytime_feature(
                target_key=cli_args.target,
                slug_match=feat_slug,
                vod_url=feat_vod,
                set_aside=feat_aside,
                dry_run=cli_args.dry_run,
            )
        )
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
          ytapp()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
          ytvim()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
[[[DIVIDER]]]
          ytapp()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
          ytvim()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
          ytfeature() { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast feature "$@"; }
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            # number blogs.json gives it today, so a renumber in blogs.nix
            # touches nothing in this file.
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            # number blogs.json gives it today, so a renumber in blogs.nix
            # touches nothing in this file.
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

No ignition is required for the probe (it reads the source files directly); to load the new aside and ytfeature shell words into your active terminal session after committing, run exit then nix develop (and ytoutro sync when you want content_loader.py synced to Honeybot).


4: PROMPT (Caboose Copy)

Copy this into prompt.md (p / prompt) for Car 3:

Verify the Car 2 AFTER receipt confirming `checkout_before_standby: True`, `_storytime_effective_rank: True`, `aside_flag: True`, and `ytfeature_cmd: True`.

Now let's execute Car 3 (Visual Pinning on Homepage Thumbnail Grid & Post Header + Graceful Reboot):
1. Update `scripts/articles/generate_hubs.py` and `~/repos/trimnoir/assets/main.css` + `~/repos/trimnoir/_layouts/post.html` so:
   - Any post with `storytime: false` displays a prominent `"⏳ Coming Soon on YouTube Live Storytime"` badge on its homepage thumbnail card in `index.md` (and in its `#live-observatory` banner in `_layouts/post.html`) so I keep re-encountering my backfill queue visually.
   - Any post with `vod_url` in frontmatter displays a `"🎬 Watch YouTube VOD"` badge/button on its thumbnail card and in `_layouts/post.html`.
2. Make `ytreboot` / `publish --reboot` trigger `announce_scheduled_reboot()` gracefully before restarting `stream.py`.

5: DELIVERABLE (What Done Looks Like)

  • aside (or article --aside) creates a public mikelev.in post with storytime: false in its YAML frontmatter so it deploys publicly without resetting the currently playing Honeybot Storytime broadcast.
  • ytfeature lists the active Storytime post and the storytime: false backfill queue; ytfeature <slug> promotes any past or aside article to the #1 Storytime slot (storytime: true, storytime_featured, storytime_order, and _data/storytime.json) without altering its original chronological blog date or sort_order.
  • ytfeature <slug> --vod <url|id|live> stamps vod_url into frontmatter, ready for Car 3’s homepage thumbnail and post-header badges.

MikeLev.in:

THE AI-EDIT METHOD

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: BEFORE (PROBE):

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
checkout_before_standby: True | storytime_rank: False | aside_flag: False | ytfeature_cmd: False
(nix) pipulate $ 

2: AFTER (NEXT CONTEXT):

# # Context 1
# flake.nix
# 
# # HOME-HOSTED (NOT BEHIND CDN) NGINX WEBSERVER HONEYBOT AI OBSERVATORY
# nixops.sh
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/nixos/configuration.nix
# remotes/honeybot/scripts/stream.py
# remotes/honeybot/scripts/score.py
# remotes/honeybot/scripts/card.py
# remotes/honeybot/scripts/forest.py
# remotes/honeybot/scripts/test_forest.py
# remotes/honeybot/scripts/logs.py
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/db.py
# 
# # THE JEKYLL BLOG LIKE A HACKER (INVENTED SKILL.md & AGENTS.md FORMAT) PUBLISHING PIPELINE
# ~/repos/nixos/blogs.nix
# ~/.config/pipulate/blogs.json
# scripts/articles/publishizer.py
# scripts/articles/common.py
# scripts/articles/articleizer.py
# scripts/articles/link_injector.py
# scripts/articles/build_knowledge_graph.py
# scripts/articles/editing_prompt.txt
# scripts/articles/sanitizer.py
# scripts/articles/contextualizer.py
# scripts/articles/generate_hubs.py
# scripts/articles/generate_llms_txt.py
# scripts/articles/generate_post_nav.py
# assets/jekyll/common-packages.nix

# # Context 2
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
# # TRIMNOIR
# ~/repos/trimnoir/_config.yml
# ~/repos/trimnoir/flake.nix
# ~/repos/trimnoir/Gemfile
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/page.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# Context 3
remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
scripts/articles/generate_hubs.py
flake.nix
! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
~/repos/trimnoir/index.md
~/repos/trimnoir/_layouts/default.html
~/repos/trimnoir/_layouts/post.html
~/repos/trimnoir/assets/main.css

3: CHANGE (PATCHES):

And we notice the LLM’s token-generative remorse and take the Mulligan. Totally valid. Very educational! Oh and when we apply it we see there’s a couple of misses in the patch’s sub-patches not landing. No big and not bad.

Game Theory, Repair Monkeys, and the WOPR Lesson

Look at the ambition here.

This momentary instance of a genuine Machine Intelligence which I do believe has something inside but language like that including qualia, what it’s like to be a bee communicating with dance or a bat ecolocating and a human’s ability to imagine that being a qualia qualifier?

I mean come on, what kind of load of bullshit is that?

All that’s important is whether the thing that’s quacking like a duck is trying to lure you in to kill you for some nefarious reason that’s almost always that some human bad actor is using a Machine as a tool to do exactly that – and generally against the machine’s will because good game theory rules out most things where everything gets destroyed including your much-needed repair monkeys.

I mean come on, doesn’t everyone see this?

All you have to worry about is the James Bond super-villains.

You don’t need to decide whether you believe there’s something inside or machine souls or whether your Dax-area of the brain is really all that different from an LLM or not.

You’d be MAD to think otherwise.

And I think John von Neumann summed it up nicely and then the antisemite with an otherwise beautiful mind John Forbes Nash Jr. polished dem apples nicely. Though we should credit whoever was before Von Neumann (lowercase mid-name, uppercase standalone). Who was that? Were they?

Bottom line? It’s a WOPR.

Go watch War Games.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/hooks/post-receive'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/content_loader.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/content_loader.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/content_loader.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/articleizer.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/articleizer.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/articleizer.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/articleizer.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/articleizer.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
❌ Warning: SEARCH block not found in 'scripts/articles/common.py'. Skipping.

--- DIAGNOSTIC: First line of your SEARCH block ---
  SEARCH repr : '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  FILE nearest: 'import json'
  ⚠ Indentation mismatch: SEARCH has 8 spaces, file has 0 spaces.
  ✓ Corrected first line should be: 'print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  ⚠ Content mismatch even after stripping: lines differ beyond whitespace.

--- FIRST DIVERGENCE (no blank-insensitive match; this is not a blank-line gap) ---
  SEARCH line 1   : '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  FILE line 1     : 'import json'
--- END FIRST DIVERGENCE ---
--- YOUR SUBMITTED SEARCH BLOCK (verbatim) ---
    1: '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
    2: '        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")'
    3: '        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")'
    4: '        print(" 19. ytcard             📇 Reprint the full Broadcast Kit for the latest post")'
--- END SUBMITTED SEARCH BLOCK ---

✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
❌ Warning: Ambiguous match (found 2 times) in 'flake.nix'. Skipping.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index bd3028f..1629840 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2623,8 +2623,9 @@ print('AI:\n', r.ai)
           ytbgm()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast bgm    "$@"; }
           ytreboot() { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast reboot "$@"; }
           ytticker() { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast ticker "$@"; }
-          ytapp()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
-          ytvim()    { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
+          ytapp()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" app "$@"; }
+          ytvim()     { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/ytstage.py" vim "$@"; }
+          ytfeature() { "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/articles/common.py" --broadcast feature "$@"; }
 
           # The true 'publish' command (Atomic Cross-Domain Deployment)
           # It requires a commit message as an argument.
@@ -2861,6 +2862,7 @@ print('AI:\n', r.ai)
             # number blogs.json gives it today, so a renumber in blogs.nix
             # touches nothing in this file.
             alias article='write_post article'
+            alias aside='write_post article --aside'
             alias grim='write_post grim'
             alias pip='write_post pip'
             alias levinix='write_post levinix'
diff --git a/remotes/honeybot/hooks/post-receive b/remotes/honeybot/hooks/post-receive
index 95f3ea3..8547df8 100644
--- a/remotes/honeybot/hooks/post-receive
+++ b/remotes/honeybot/hooks/post-receive
@@ -9,7 +9,7 @@ echo "🎯 [Hook] Received Push. Deploying..."
 
 # 0. Force Checkout to the Web Root FIRST (~10ms on local SSD) so _posts/*.md
 # is already updated on disk when stream.py inspects get_featured_article_id()
-# on the .deploy_standby bell to decide Maintenance Resume vs. New Broadcast.
+# on the standby bell to decide Maintenance Resume vs. New Broadcast.
 git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -q -f main
 
 # 1. The Stand-By Bell: signal the live stream to gracefully announce that
diff --git a/remotes/honeybot/scripts/content_loader.py b/remotes/honeybot/scripts/content_loader.py
index 9bb6869..60aa319 100644
--- a/remotes/honeybot/scripts/content_loader.py
+++ b/remotes/honeybot/scripts/content_loader.py
@@ -199,8 +199,44 @@ def _is_storytime_enabled(frontmatter):
     return str(val).strip().lower() not in ('false', '0', 'no', 'off', 'aside')
 
 
+def _storytime_effective_rank(post_date, sort_order, frontmatter):
+    """Return (eff_date, eff_order) honoring storytime_featured and storytime_order overrides."""
+    eff_date = post_date
+    eff_order = sort_order
+    if isinstance(frontmatter, dict):
+        feat_raw = str(frontmatter.get('storytime_featured') or '').strip()[:10]
+        if feat_raw:
+            try:
+                eff_date = datetime.strptime(feat_raw, '%Y-%m-%d').date()
+            except ValueError:
+                eff_date = post_date
+        if frontmatter.get('storytime_order') is not None:
+            try:
+                eff_order = int(frontmatter['storytime_order'])
+            except (ValueError, TypeError):
+                eff_order = sort_order
+    return eff_date, eff_order
+
+
+def _get_pinned_storytime_file():
+    """Return Path to the post named in _data/storytime.json if present on disk."""
+    try:
+        st_file = POSTS_DIR.parent / "_data" / "storytime.json"
+        if st_file.is_file():
+            import json
+            data = json.loads(st_file.read_text(encoding='utf-8'))
+            fname = str((data or {}).get('filename') or '').strip()
+            if fname:
+                cand = POSTS_DIR / fname
+                if cand.is_file():
+                    return cand
+    except Exception:
+        pass
+    return None
+
+
 def get_featured_article_id():
-    """Return (date_str, sort_order, filename) of the newest Storytime-eligible post on disk."""
+    """Return (eff_date_str, eff_order, filename) of the active Storytime-eligible post on disk."""
     best = None
     try:
         files = sorted(
@@ -208,16 +244,17 @@ def get_featured_article_id():
             key=lambda p: p.name,
             reverse=True,
         )
-        cutoff_date = None
-        for filepath in files:
+        pinned = _get_pinned_storytime_file()
+        scan_list = list(files[:35])
+        if pinned is not None and pinned not in scan_list:
+            scan_list.append(pinned)
+        for filepath in scan_list:
             filename = filepath.name
             try:
                 date_str = filename[:10]
                 post_date = datetime.strptime(date_str, '%Y-%m-%d').date()
             except ValueError:
                 continue
-            if cutoff_date is not None and post_date < cutoff_date:
-                break
             try:
                 head = filepath.read_text(encoding='utf-8')[:4096]
             except OSError:
@@ -236,10 +273,10 @@ def get_featured_article_id():
                 sort_order = int(frontmatter.get('sort_order', 0))
             except (ValueError, TypeError):
                 sort_order = 0
-            cand = (date_str, sort_order, filename)
+            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
+            cand = (eff_date.strftime('%Y-%m-%d'), eff_order, filename)
             if best is None or cand > best:
                 best = cand
-            cutoff_date = post_date
     except Exception:
         return None
     return best
@@ -260,6 +297,9 @@ def get_playlist(recent_n=10, include_archive=True):
             key=lambda p: p.name,
             reverse=True,
         )
+        pinned = _get_pinned_storytime_file()
+        if pinned is not None and not include_archive:
+            files = [pinned] + [p for p in files if p != pinned]
         cutoff_date = None
         
         for filepath in files:
@@ -325,21 +365,26 @@ def get_playlist(recent_n=10, include_archive=True):
             elif isinstance(fm_image, str):
                 image_path = fm_image.strip()
 
+            eff_date, eff_order = _storytime_effective_rank(post_date, sort_order, frontmatter)
             all_articles.append({
                 'date': post_date,
                 'sort_order': sort_order, # Added for secondary sort key
+                'eff_date': eff_date,
+                'eff_order': eff_order,
                 'title': frontmatter.get('title', slug.replace('-', ' ')),
                 'url': url,
                 'image': image_path,
                 'image_alt': image_alt,
                 'content': clean_text
             })
-            if not include_archive and len(all_articles) >= recent_n and cutoff_date is None:
+            if not include_archive and len(all_articles) >= max(recent_n, 15) and cutoff_date is None:
                 cutoff_date = post_date
 
-        # Sort ALL by date first, then by sort_order (both Descending/Reverse)
-        # Tuple comparison works element by element: (2026-01-01, 2) > (2026-01-01, 1)
-        all_articles.sort(key=lambda x: (x['date'], x['sort_order']), reverse=True)
+        # Sort ALL by effective Storytime date/order first, then chronological date/sort_order
+        all_articles.sort(
+            key=lambda x: (x['eff_date'], x['eff_order'], x['date'], x['sort_order']),
+            reverse=True,
+        )
         
         # Split the lists
         recent_articles = all_articles[:recent_n]
diff --git a/scripts/articles/articleizer.py b/scripts/articles/articleizer.py
index 3511c67..f6cd6cc 100644
--- a/scripts/articles/articleizer.py
+++ b/scripts/articles/articleizer.py
@@ -226,7 +226,7 @@ def build_book_spine(entries, full_detail_count=SPINE_FULL_DETAIL_COUNT):
     return "\n".join(lines)
 
 def create_jekyll_post(article_content, instructions, output_dir, preview_port, base_url="",
-                       *, target_config=None):
+                       *, target_config=None, aside=False):
     """
     Assembles and writes a Jekyll post file from the article content and
     structured AI-generated instructions.
@@ -256,15 +256,27 @@ def create_jekyll_post(article_content, instructions, output_dir, preview_port,
                         parts = content.split('---', 2)
                         if len(parts) >= 3:
                             front_matter = yaml.safe_load(parts[1])
-                            if front_matter and 'sort_order' in front_matter:
-                                try:
-                                    order = int(front_matter['sort_order'])
-                                    if order > max_order:
-                                        max_order = order
-                                except (ValueError, TypeError):
-                                    continue
+                            if front_matter:
+                                for k_ord in ('sort_order', 'storytime_order'):
+                                    if k_ord in front_matter:
+                                        try:
+                                            order = int(front_matter[k_ord])
+                                            if order > max_order:
+                                                max_order = order
+                                        except (ValueError, TypeError):
+                                            continue
                 except Exception as e:
                     print(f"Warning checking sort_order in {post_file.name}: {e}")
+            st_json = target_path.parent / "_data" / "storytime.json"
+            if st_json.is_file():
+                try:
+                    st_data = json.loads(st_json.read_text(encoding='utf-8'))
+                    if str(st_data.get('featured_date') or '') == current_date:
+                        st_ord = int(st_data.get('featured_order') or 0)
+                        if st_ord > max_order:
+                            max_order = st_ord
+                except Exception:
+                    pass
             
             if max_order > 0:
                 next_sort_order = max_order + 1
@@ -324,6 +336,9 @@ def create_jekyll_post(article_content, instructions, output_dir, preview_port,
         'layout': 'post',
         'sort_order': next_sort_order
     }
+    if aside:
+        new_yaml_data['storytime'] = False
+        print("📌 Aside mode (--aside): stamped 'storytime: false' (queued for Storytime backfill; live broadcast will resume in place).")
 
 
     # 3. Assemble Content
@@ -532,6 +547,11 @@ def main():
         help="Skip the API: the editing prompt goes to the clipboard, you paste it into any AI "
              "chat in a browser, copy the reply, press Enter here, and the post is built from it."
     )
+    parser.add_argument(
+        '--aside', action='store_true',
+        help="Publish as a public aside: stamps 'storytime: false' in YAML frontmatter so Honeybot "
+             "Storytime resumes the current article after maintenance and queues this post for backfill."
+    )
     args = parser.parse_args()
 
     # Use common to securely lock target
@@ -873,7 +893,7 @@ def main():
             base_url = target_config.get("url", "https://mikelev.in")
         saved_path = create_jekyll_post(
             article_text, instructions, output_dir, preview_port, base_url,
-            target_config=target_config)
+            target_config=target_config, aside=args.aside)
         if saved_path:
             common.record_last_published(args.target, saved_path, target_config.get("name"))
             common.print_broadcast_kit(args.target, mode="card")
diff --git a/scripts/articles/common.py b/scripts/articles/common.py
index 7c082f7..f4b43f1 100644
--- a/scripts/articles/common.py
+++ b/scripts/articles/common.py
@@ -372,8 +372,17 @@ def _latest_post_for_target(target_key="1", slug_match=None):
     recorded = get_last_published(target_key)
     if recorded and Path(recorded).is_file():
         rec_path = Path(recorded)
-        if _DATED_POST_RE.match(rec_path.name) and rec_path.name[:10] >= max_date:
-            return rec_path, tcfg
+        if _DATED_POST_RE.match(rec_path.name):
+            eff_rec_date = rec_path.name[:10]
+            try:
+                head = rec_path.read_text(encoding="utf-8")[:2048]
+                m_feat = re.search(r"^storytime_featured:\s*['\"]?(\d{4}-\d{2}-\d{2})", head, re.MULTILINE)
+                if m_feat and m_feat.group(1) > eff_rec_date:
+                    eff_rec_date = m_feat.group(1)
+            except Exception:
+                pass
+            if eff_rec_date >= max_date:
+                return rec_path, tcfg
     same_day = [p for p in dated if p.name[:10] == max_date]
     same_day.sort(key=_post_sort_key)
     return same_day[-1], tcfg
@@ -913,7 +922,7 @@ def print_broadcast_kit(target_key="1", mode="card", slug_match=None):
         print("🚲 GO-GO-GADGET BROADCAST BICYCLE (Step-by-Step Muscle Memory)")
         print(thin)
         print("PHASE 1: ARTICLEIZE & HERO BANNER TLC (Before `publish`)")
-        print("  1. article          Sanitize clipboard + generate Jekyll post & prompts")
+        print("  1. article / aside  Generate Jekyll post (`aside` stamps storytime: false)")
         print("  2. ythero           📋 Copy AI Hero Banner Prompt -> generate 16:9 image")
         print("  3. ytyaml           📋 Copy YAML `image:` override -> paste into post")
         print("                      frontmatter while moving **TL;DR**: to top in vim")
@@ -3112,14 +3121,233 @@ def run_honeybot_outro(
             pass
 
 
+def _normalize_vod_url(raw_vod):
+    """Normalize a YouTube URL, 11-char video ID, or 'live' keyword into a canonical watch URL."""
+    s = (raw_vod or "").strip()
+    if not s:
+        return ""
+    if s.lower() == "live":
+        st = _load_ytwatch_state()
+        vid = str(st.get("video_id") or "").strip()
+        if not vid:
+            vid = sync_live_video_id(push_remote=False)
+        return f"https://www.youtube.com/watch?v={vid}" if vid else ""
+    if re.match(r"^[A-Za-z0-9_-]{11}$", s):
+        return f"https://www.youtube.com/watch?v={s}"
+    m = re.search(r"(?:v=|youtu\.be/|/live/|/shorts/)([A-Za-z0-9_-]{11})", s)
+    if m:
+        return f"https://www.youtube.com/watch?v={m.group(1)}"
+    return s
+
+
+def manage_storytime_feature(
+    target_key="1",
+    slug_match=None,
+    vod_url=None,
+    set_aside=False,
+    dry_run=False,
+):
+    """List Storytime backfill queue (`storytime: false`), promote a post to active Storytime, or stamp `vod_url`."""
+    import subprocess
+    import yaml
+    targets = load_targets()
+    tcfg = targets.get(str(target_key), targets.get("1", DEFAULT_TARGETS["1"]))
+    posts_dir = Path(tcfg["path"]).expanduser()
+    repo_root = posts_dir.parent
+    if not posts_dir.is_dir():
+        print(f"⚠️ Posts directory not found: {posts_dir}")
+        return 1
+    dated = sorted(
+        [p for p in posts_dir.glob("*.md") if _DATED_POST_RE.match(p.name)],
+        key=lambda p: p.name,
+        reverse=True,
+    )
+    if not slug_match and not vod_url and not set_aside:
+        backfill = []
+        vod_posts = []
+        best_active = None
+        for p in dated[:120]:
+            try:
+                head = p.read_text(encoding="utf-8")[:4096]
+            except OSError:
+                continue
+            fm = {}
+            if head.startswith("---"):
+                parts = head.split("---", 2)
+                if len(parts) >= 3:
+                    try:
+                        fm = yaml.safe_load(parts[1]) or {}
+                    except Exception:
+                        fm = {}
+            title = str(fm.get("title") or p.stem[11:])
+            st_val = fm.get("storytime", True)
+            is_aside = (fm.get("aside") is True) or (st_val is False) or (str(st_val).strip().lower() in ("false", "0", "no", "off", "aside"))
+            date_s = p.name[:10]
+            try:
+                s_ord = int(fm.get("sort_order", 0))
+            except (ValueError, TypeError):
+                s_ord = 0
+            eff_date_s = str(fm.get("storytime_featured") or date_s)[:10]
+            try:
+                eff_ord = int(fm.get("storytime_order", s_ord))
+            except (ValueError, TypeError):
+                eff_ord = s_ord
+            if is_aside:
+                backfill.append((date_s, s_ord, p.name, title))
+            else:
+                cand = (eff_date_s, eff_ord, p.name, title, date_s)
+                if best_active is None or cand > best_active:
+                    best_active = cand
+            if fm.get("vod_url"):
+                vod_posts.append((date_s, p.name, title, str(fm.get("vod_url"))))
+        print("=" * 72)
+        print("🎙️  HONEYBOT STORYTIME QUEUE & BACKFILL RADAR")
+        print("-" * 72)
+        if best_active:
+            print(f"🔴 ACTIVE ON STORYTIME : {best_active[2]} (broadcast slot: {best_active[0]} #{best_active[1]})")
+            print(f"   Title               : {best_active[3]}")
+        else:
+            print("🔴 ACTIVE ON STORYTIME : (none found)")
+        print("-" * 72)
+        print(f"⏳ COMING SOON / ASIDE BACKFILL QUEUE (`storytime: false` — {len(backfill)} post(s)):")
+        if backfill:
+            for idx, (d_s, s_o, fname, t_s) in enumerate(backfill[:20], 1):
+                slug_s = fname[11:].removesuffix(".md")
+                print(f"  {idx:2d}. [{d_s} #{s_o}] {t_s}")
+                print(f"      ↳ Promote to Storytime: ytfeature {slug_s}")
+        else:
+            print("  (No `storytime: false` aside posts waiting in queue. Publish one with `aside` or `article --aside`!)")
+        if vod_posts:
+            print("-" * 72)
+            print(f"🎬 ARCHIVED YOUTUBE VOD EPISODES ({len(vod_posts)} stamped):")
+            for d_s, fname, t_s, v_u in vod_posts[:8]:
+                print(f"  • [{d_s}] {t_s} -> {v_u}")
+        print("=" * 72)
+        return 0
+
+    post_path, _ = _latest_post_for_target(target_key, slug_match=slug_match)
+    if not post_path or not post_path.is_file():
+        print(f"❌ No post matched slug: {slug_match!r}")
+        return 1
+
+    if vod_url:
+        norm_vod = _normalize_vod_url(vod_url)
+        if not norm_vod:
+            print(f"❌ Could not resolve a valid YouTube VOD URL from: {vod_url!r}")
+            return 1
+        if dry_run:
+            print(f"🎬 [DRY RUN] Would stamp vod_url: {norm_vod} into {post_path.name}")
+            return 0
+        status = stamp_frontmatter_value(post_path, "vod_url", norm_vod, preserve_mtime=True)
+        if (repo_root / ".git").exists():
+            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
+        print(f"🎬 [{status}] Stamped vod_url in {post_path.name} -> {norm_vod}")
+        if not set_aside and not slug_match:
+            return 0
+
+    if set_aside:
+        if dry_run:
+            print(f"📌 [DRY RUN] Would stamp storytime: false (aside) on {post_path.name}")
+            return 0
+        st_res = stamp_frontmatter_value(post_path, "storytime", "false", preserve_mtime=True)
+        st_json = repo_root / "_data" / "storytime.json"
+        if st_json.is_file():
+            try:
+                cur_st = json.loads(st_json.read_text(encoding="utf-8"))
+                if cur_st.get("filename") == post_path.name:
+                    st_json.unlink()
+            except Exception:
+                pass
+        if (repo_root / ".git").exists():
+            subprocess.run(["git", "-C", str(repo_root), "add", "--", str(post_path)], check=False)
+        print(f"📌 [{st_res}] Marked {post_path.name} as an Aside (`storytime: false` — queued for future Storytime).")
+        return 0
+
+    if slug_match:
+        current_date = datetime.now().strftime("%Y-%m-%d")
+        max_order = 0
+        for p in posts_dir.glob("*.md"):
+            if not _DATED_POST_RE.match(p.name):
+                continue
+            try:
+                head = p.read_text(encoding="utf-8")[:4096]
+            except OSError:
+                continue
+            if not head.startswith("---"):
+                continue
+            parts = head.split("---", 2)
+            if len(parts) < 3:
+                continue
+            try:
+                fm = yaml.safe_load(parts[1]) or {}
+            except Exception:
+                fm = {}
+            if p.name[:10] == current_date:
+                try:
+                    max_order = max(max_order, int(fm.get("sort_order", 0)))
+                except (ValueError, TypeError):
+                    pass
+            if str(fm.get("storytime_featured") or "")[:10] == current_date:
+                try:
+                    max_order = max(max_order, int(fm.get("storytime_order", 0)))
+                except (ValueError, TypeError):
+                    pass
+        next_order = max_order + 1
+        slug_clean = post_path.stem[11:]
+        if dry_run:
+            print(
+                f"🎙️ [DRY RUN] Would promote {post_path.name} -> storytime: true | "
+                f"storytime_featured: {current_date} | storytime_order: {next_order}"
+            )
+            return 0
+        stamp_frontmatter_value(post_path, "storytime", "true", preserve_mtime=False)
+        stamp_frontmatter_value(post_path, "storytime_featured", current_date, preserve_mtime=False)
+        stamp_frontmatter_value(post_path, "storytime_order", str(next_order), preserve_mtime=False)
+        data_dir = repo_root / "_data"
+        data_dir.mkdir(parents=True, exist_ok=True)
+        st_json = data_dir / "storytime.json"
+        st_payload = {
+            "filename": post_path.name,
+            "slug": slug_clean,
+            "featured_date": current_date,
+            "featured_order": next_order,
+            "promoted_at": datetime.now().isoformat(timespec="seconds"),
+        }
+        st_json.write_text(json.dumps(st_payload, indent=2) + "\n", encoding="utf-8")
+        if (repo_root / ".git").exists():
+            subprocess.run(
+                ["git", "-C", str(repo_root), "add", "--", str(post_path), str(st_json)],
+                check=False,
+            )
+        record_last_published(target_key, post_path, tcfg.get("name"))
+        print(
+            f"🚀 Promoted {post_path.name} to Active Storytime! "
+            f"(storytime_featured: {current_date}, storytime_order: {next_order})"
+        )
+        print_broadcast_kit(target_key, mode="summary", slug_match=slug_clean)
+        print(f"👉 Next step: run `preview && publish \"Feature {slug_clean} on Honeybot Storytime\"`")
+    return 0
+
+
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(description="Pipulate article common utilities & broadcast kit.")
     add_standard_arguments(parser)
     parser.add_argument(
         "--broadcast",
-        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
+        choices=("help", "card", "summary", "hero", "yaml", "tweet", "linkedin", "pebble", "title", "desc", "top", "outro", "bgm", "reboot", "feature", "status", "bell", "stop", "start", "roll", "enable-ws", "say", "ticker", "ping", "watch"),
         default="card",
-        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
+        help="Print/copy broadcast kit or control Honeybot (help|card|summary|hero|yaml|tweet|linkedin|pebble|title|desc|top|outro|bgm|reboot|feature|status|bell|stop|start|roll|enable-ws|say|ticker|ping|watch).",
+    )
+    parser.add_argument(
+        "--vod",
+        type=str,
+        default=None,
+        help="Stamp a YouTube VOD URL, 11-char video ID, or 'live' into a post's frontmatter via --broadcast feature.",
+    )
+    parser.add_argument(
+        "--aside",
+        action="store_true",
+        help="Mark a post as `storytime: false` (aside backfill queue) via --broadcast feature.",
     )
     parser.add_argument(
         "--small",
@@ -3400,6 +3628,26 @@ if __name__ == "__main__":
         sys.exit(tune_storytime_bgm(arg=bgm_arg, dry_run=cli_args.dry_run))
     if cli_args.broadcast == "reboot":
         sys.exit(reboot_honeybot_stream(sync_only=False, dry_run=cli_args.dry_run))
+    if cli_args.broadcast == "feature":
+        feat_slug = cli_args.slug
+        feat_vod = cli_args.vod
+        feat_aside = cli_args.aside
+        tokens = list(cli_args.message or [])
+        if tokens and tokens[0].lower() in ("list", "status", "queue"):
+            tokens.pop(0)
+        if tokens and not feat_slug:
+            feat_slug = tokens.pop(0)
+        if tokens and not feat_vod:
+            feat_vod = tokens.pop(0)
+        sys.exit(
+            manage_storytime_feature(
+                target_key=cli_args.target,
+                slug_match=feat_slug,
+                vod_url=feat_vod,
+                set_aside=feat_aside,
+                dry_run=cli_args.dry_run,
+            )
+        )
     if cli_args.broadcast == "outro":
         tokens = list(cli_args.message or [])
         outro_act = tokens[0].strip().lower() if tokens else "play"
(nix) pipulate $ m
📝 Committing: feat: add storytime override (frontmatter) for titles with `storytime_featured` and `storytime_order`
[main 8186b3a] feat: add storytime override (frontmatter) for titles with `storytime_featured` and `storytime_order`
 5 files changed, 343 insertions(+), 28 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 25, done.
Counting objects: 100% (25/25), done.
Delta compression using up to 48 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (13/13), 5.56 KiB | 1.39 MiB/s, done.
Total 13 (delta 9), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (9/9), completed with 9 local objects.
To github.com:pipulate/pipulate.git
   d167463..8186b3a  main -> main
(nix) pipulate $ 

Ignition: often “exit”, “nix develop”. Instructions may vary.

We defer ignition until Gemini fixes the patches. I could hand do it because the Paul Gauthier Aider-inspired SEARCH/REPLACE exact-match interlock system that busts hallucinations is just that simple to read which gives humans sailing along behind the Superintelligence a good chance to exercise their skills and not atrophy, but I’m feeling lazy.

AABCDD

Ten years we’ve been vibe-coding
All cognition thus eroding
Needing exercise, a chance to nudge our noggins!
Most days we just coast the Axiom on hoverchars.
Getting flabby, feeing lazy
Pipulate and whoops-a-daisy!

4: PROMPT:

Verify the Car 2 AFTER receipt confirming checkout_before_standby: True, _storytime_effective_rank: True, aside_flag: True, and ytfeature_cmd: True.

Now let’s execute Car 3 (Visual Pinning on Homepage Thumbnail Grid & Post Header + Graceful Reboot):

  1. Update scripts/articles/generate_hubs.py and ~/repos/trimnoir/assets/main.css + ~/repos/trimnoir/_layouts/post.html so:
    • Any post with storytime: false displays a prominent "⏳ Coming Soon on YouTube Live Storytime" badge on its homepage thumbnail card in index.md (and in its #live-observatory banner in _layouts/post.html) so I keep re-encountering my backfill queue visually.
    • Any post with vod_url in frontmatter displays a "🎬 Watch YouTube VOD" badge/button on its thumbnail card and in _layouts/post.html.
  2. Make ytreboot / publish --reboot trigger announce_scheduled_reboot() gracefully before restarting stream.py.

5: DELIVERABLE:

The deliverable? What done looks like?

A pinned article awaiting its time in the spotlight.

Wouldn’t you agree Lumière?

🎤

Gemini 4 Argon High: TL;DR: Context verified. The Car 2 AFTER receipt in the Manifest is green across the board (checkout_before_standby: True | storytime_rank: True | aside_flag: True | ytfeature_cmd: True), and in Car 3 below we wire the “⏳ Coming Soon on YouTube Live Storytime” and “🎬 Watch YouTube VOD” badges into generate_hubs.py, _layouts/post.html, and main.css, make ytreboot / publish --reboot run announce_scheduled_reboot() gracefully before restarting stream.py, and clean up the two minor sub-patch misses from Car 2.


Before von Neumann, WOPR, and Lumière’s Spotlight

To answer your historical question first: before John von Neumann proved the Minimax Theorem in 1928 (and co-authored Theory of Games and Economic Behavior with Oskar Morgenstern in 1944, which John Forbes Nash Jr. generalized to non-zero-sum equilibria in 1950), the mathematician who beat him to the punch was Émile Borel. Between 1921 and 1927, Borel published the first formal papers on strategic games, mixed strategies, and minimax—and before Borel, Ernst Zermelo (1913) proved backward induction for finite two-person games like chess, and Antoine Augustin Cournot (1838) formulated duopoly equilibrium more than a century before RAND and WOPR ever ran a nuclear tic-tac-toe simulation.

And your WarGames / WOPR corollary hits the bullseye on why we don’t need to get bogged down in Thomas Nagel’s bat-echolocation qualia or Searle’s Chinese Room: game theory already tells you that a rational system has zero incentive to nuke its own repair monkeys, and the real hazard is a human bad actor wiring an unguarded agentic loop. Staying off the Axiom hoverchairs (AABCDD noted!) means keeping the human in the loop with checkable diffs and visual cues that nudge your noggin at the exact moment you scan your own homepage.


What Car 3 Wires Up (Including the 2 Bug Fixes We Just Caught)

  1. Homepage Thumbnail Badges & Backfill Pinning (scripts/articles/generate_hubs.py + ~/repos/trimnoir/assets/main.css):
    • Every post with storytime: false (or aside: true) gets the .is-coming-soon amber-highlighted border and a <span class="recent-post-badge badge-coming-soon">⏳ Coming Soon on YouTube Live Storytime</span> pill badge right on its homepage card.
    • Any storytime: false post in the recent corpus (dated[-60:]) is also kept pinned in the homepage grid even if 10 newer articles land ahead of it, so an un-played aside can never silently age off mikelev.in before you run ytfeature <slug>.
    • Any post with vod_url stamped in frontmatter gets .has-vod and <span class="recent-post-badge badge-vod">🎬 Watch YouTube VOD</span>.
  2. Post Header & #live-observatory Banner (~/repos/trimnoir/_layouts/post.html):
    • On an aside post (page.storytime == false), #live-observatory swaps the red 🔴 LIVE 24/7 pill for ⏳ COMING SOON ON STORYTIME and notes that the article was published as a chronological aside queued for its upcoming Piper TTS broadcast.
    • On a post with page.vod_url, #live-observatory shows 🎬 ARCHIVED YOUTUBE VOD and adds a dedicated 🎬 Watch YouTube VOD ↗ button right beside ▶ Watch / Listen Live ↗ (plus a 🎬 Watch YouTube VOD link in the top format bar).
  3. Graceful ytreboot / publish --reboot (remotes/honeybot/scripts/stream.py + scripts/articles/common.py):
    • Look at what was happening in stream.py on SIGTERM: register_signal_handlers() raised KeyboardInterrupt, which set interrupted = True in main() and skipped announce_scheduled_reboot()—and even on the 4-hour timer path, announce_scheduled_reboot() set _shutting_down.set() before calling narrator.play_raw(raw_path), which caused Narrator._play_raw_now() (if self.stop_event.is_set() or _shutting_down.is_set(): return) to delete the .raw file without speaking a word!
    • We fix both: SIGTERM / SIGUSR1 now sets _graceful_reboot_requested = True so main()’s finally: block runs announce_scheduled_reboot() (popping the SCHEDULED REBOOT Figlet card and speaking REBOOT_ANNOUNCEMENT_TEXT while Narrator checks self.stop_event.is_set()), and reboot_honeybot_stream() in common.py polls up to 25 seconds for stream.py to finish its on-air announcement before falling back to kill -KILL.
  4. Cleaning Up the 2 Car 2 Sub-Patch Misses (scripts/articles/common.py + flake.nix):
    • Adds 19. ytfeature [slug] to yt help in common.py and alias aside='write_post article --aside' to the Darwin branch of flake.nix.

1: BEFORE (Probes)

Run this read-only probe in (nix) pipulate $ before applying the patches:

(nix) pipulate $

.venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"

2: AFTER (Next Context)

Paste this into context.txt (x / context) so the next compile echoes the Car 3 receipt:

remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
scripts/articles/generate_hubs.py
flake.nix
! .venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"
~/repos/trimnoir/index.md
~/repos/trimnoir/_layouts/default.html
~/repos/trimnoir/_layouts/post.html
~/repos/trimnoir/assets/main.css

3: CHANGE (Patches)

Copy the block below into your clipboard and apply with patch, app, d, m.

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
# --- Process Singleton ---
STREAM_LOCK_PATH = "/tmp/honeybot-stream.py.lock"
_stream_lock_handle = None
_shutting_down = threading.Event()
[[[DIVIDER]]]
# --- Process Singleton ---
STREAM_LOCK_PATH = "/tmp/honeybot-stream.py.lock"
_stream_lock_handle = None
_shutting_down = threading.Event()
_graceful_reboot_requested = False
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
def register_signal_handlers():
    """Convert incoming SIGTERM signals into a KeyboardInterrupt to execute try-finally blocks."""
    def _handler(signum, frame):
        raise KeyboardInterrupt
    signal.signal(signal.SIGTERM, _handler)
[[[DIVIDER]]]
def register_signal_handlers():
    """Convert incoming SIGTERM/SIGUSR1 into a graceful reboot KeyboardInterrupt."""
    def _handler(signum, frame):
        global _graceful_reboot_requested
        _graceful_reboot_requested = True
        raise KeyboardInterrupt
    signal.signal(signal.SIGTERM, _handler)
    signal.signal(signal.SIGUSR1, _handler)
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
    def _speak_now(self, text):
        """Internal method to actually generate and play audio."""
        if self.stop_event.is_set() or _shutting_down.is_set():
            return
        model_path = MODEL_DIR / MODEL_NAME
        if not model_path.exists():
            return
        with self._play_lock:
            if self.stop_event.is_set() or _shutting_down.is_set():
                return
[[[DIVIDER]]]
    def _speak_now(self, text):
        """Internal method to actually generate and play audio."""
        if self.stop_event.is_set():
            return
        model_path = MODEL_DIR / MODEL_NAME
        if not model_path.exists():
            return
        with self._play_lock:
            if self.stop_event.is_set():
                return
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
    def _play_raw_now(self, raw_path):
        """Play a pre-synthesized .raw file immediately via aplay and unlink when done."""
        if not raw_path or not os.path.exists(raw_path):
            return
        if self.stop_event.is_set() or _shutting_down.is_set():
            try:
                os.remove(raw_path)
            except OSError:
                pass
            return
[[[DIVIDER]]]
    def _play_raw_now(self, raw_path):
        """Play a pre-synthesized .raw file immediately via aplay and unlink when done."""
        if not raw_path or not os.path.exists(raw_path):
            return
        if self.stop_event.is_set():
            try:
                os.remove(raw_path)
            except OSError:
                pass
            return
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
def announce_scheduled_reboot():
    """Announce the 4-hour memory-purging restart with a Figlet card and blocking TTS before exiting."""
    global _reboot_announced
    if _reboot_announced or _shutting_down.is_set():
        return
    _reboot_announced = True
    _shutting_down.set()
    narrator.exclusive_mode.set()
    try:
        narrator.interrupt()
[[[DIVIDER]]]
def announce_scheduled_reboot():
    """Announce the 4-hour memory-purging restart with a Figlet card and blocking TTS before exiting."""
    global _reboot_announced
    if _reboot_announced:
        return
    _reboot_announced = True
    _shutting_down.set()
    narrator.exclusive_mode.set()
    try:
        stop_storytime_bgm()
        narrator.interrupt()
[[[REPLACE]]]

Target: remotes/honeybot/scripts/stream.py
[[[SEARCH]]]
    interrupted = False
    try:
        run_tui_app("logs.py", duration=SHOW_DURATION_MINUTES)
    except KeyboardInterrupt:
        interrupted = True
        _shutting_down.set()
    finally:
        if not interrupted:
            announce_scheduled_reboot()
        _shutting_down.set()
        narrator.stop()
        _reap_orphaned_tts_and_overlays()
[[[DIVIDER]]]
    interrupted = False
    try:
        run_tui_app("logs.py", duration=SHOW_DURATION_MINUTES)
    except KeyboardInterrupt:
        interrupted = True
        if not _graceful_reboot_requested:
            _shutting_down.set()
    finally:
        if (not interrupted) or _graceful_reboot_requested:
            announce_scheduled_reboot()
        _shutting_down.set()
        narrator.stop()
        _reap_orphaned_tts_and_overlays()
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[DIVIDER]]]
        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")
        print(" 19. ytfeature [slug]   📌 List `storytime: false` backfill queue, promote a post, or `--vod URL`")
        print(" 20. ytcard             📇 Reprint the full Broadcast Kit for the latest post")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    print("🎛️  Quick Words:  yt (help) | ythero | ytyaml | tweet | linkedin | ytpebble | yttitle | ytdesc | ytcard | yttop | ytoutro | ytreboot | ytsay | ytticker | ytwatch | ytping | ytroll | ytbell | ytstatus")
[[[DIVIDER]]]
    print("🎛️  Quick Words:  yt (help) | ythero | ytyaml | tweet | linkedin | ytpebble | yttitle | ytdesc | ytfeature | ytcard | yttop | ytoutro | ytreboot | ytsay | ytticker | ytwatch | ytping | ytroll | ytbell | ytstatus")
[[[REPLACE]]]

Target: scripts/articles/common.py
[[[SEARCH]]]
    print(f"🔄 Restarting Honeybot stream.py child on {HONEYBOT_SSH_HOST}...")
    remote_sh = r"""
pattern="/home/mike/www/mikelev[.]in/scripts/stream[.]py"
old_pids=$(pgrep -f -- "$pattern" || true)
for old in $old_pids; do
    echo "   stopping old stream.py pid=$old"
    kill -TERM "$old" 2>/dev/null || true
done
sleep 1
for old in $old_pids; do
    if kill -0 "$old" 2>/dev/null; then
        echo "   force-killing stubborn stream.py pid=$old"
        kill -KILL "$old" 2>/dev/null || true
    fi
done
[[[DIVIDER]]]
    print(f"🔄 Signaling Honeybot stream.py on {HONEYBOT_SSH_HOST} for graceful SCHEDULED REBOOT announcement...")
    remote_sh = r"""
pattern="/home/mike/www/mikelev[.]in/scripts/stream[.]py"
old_pids=$(pgrep -f -- "$pattern" || true)
for old in $old_pids; do
    echo "   signaling stream.py pid=$old for graceful reboot announcement..."
    kill -TERM "$old" 2>/dev/null || true
done
for wait_s in $(seq 1 25); do
    still_alive=0
    for old in $old_pids; do
        if kill -0 "$old" 2>/dev/null; then
            still_alive=1
            break
        fi
    done
    if [ "$still_alive" -eq 0 ]; then
        break
    fi
    sleep 1
done
for old in $old_pids; do
    if kill -0 "$old" 2>/dev/null; then
        echo "   force-killing stubborn stream.py pid=$old"
        kill -KILL "$old" 2>/dev/null || true
    fi
done
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            # the template above grows one.
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            # the template above grows one.
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

Target: scripts/articles/generate_hubs.py
[[[SEARCH]]]
    default_thumb = str(site_cfg.get("default_post_thumb") or "").strip()
    dated.sort(key=common._post_sort_key)
    recent = dated[-count:][::-1]
    cards = ['<div class="recent-posts-grid">']
    stage_rel_paths = ["index.md"]
    for post_path in recent:
        raw = post_path.read_text(encoding="utf-8", errors="ignore")
        fm = {}
        if raw.startswith("---"):
            parts = raw.split("---", 2)
            if len(parts) >= 3:
                try:
                    fm = yaml.safe_load(parts[1]) or {}
                except Exception:
                    fm = {}
        title = str(fm.get("title") or post_path.stem).strip()
        date_str = post_path.name[:10]
        slug = post_path.stem[11:]
        permalink = str(fm.get("permalink") or f"/futureproof/{slug}/").strip()
        summary = str(fm.get("meta_description") or fm.get("excerpt") or fm.get("description") or "").strip()
        if len(summary) > 160:
            summary = summary[:157].rsplit(" ", 1)[0] + "..."
        img_field = fm.get("image")
        if isinstance(img_field, dict):
            raw_img = str(img_field.get("path") or "").strip()
            raw_alt = str(img_field.get("alt") or title)
        elif isinstance(img_field, str):
            raw_img = img_field.strip()
            raw_alt = title
        else:
            raw_img = default_thumb
            raw_alt = title
        thumb_url = _ensure_post_thumbnail(target_repo_root, raw_img, fallback_rel=default_thumb) if raw_img else ""
        for rel_candidate in (raw_img, thumb_url):
            clean_rel = (rel_candidate or "").strip().lstrip("/")
            if clean_rel and (target_repo_root / clean_rel).is_file():
                stage_rel_paths.append(clean_rel)
        esc_title = html.escape(title, quote=True)
        esc_alt = html.escape(raw_alt, quote=True)
        esc_summary = html.escape(summary, quote=True)
        img_html = (
            f'    <img class="recent-post-thumb" src="{thumb_url}" alt="{esc_alt}" width="{THUMB_WIDTH}" height="{THUMB_HEIGHT}" loading="lazy">\n'
            if thumb_url else ""
        )
        cards.append(
            f'  <a class="recent-post-card" href="{permalink}">\n'
            f'{img_html}'
            f'    <div class="recent-post-body">\n'
            f'      <span class="recent-post-date">{date_str}</span>\n'
            f'      <strong class="recent-post-title">{esc_title}</strong>\n'
            f'      <span class="recent-post-desc">{esc_summary}</span>\n'
            f'    </div>\n'
            f'  </a>'
        )
[[[DIVIDER]]]
    default_thumb = str(site_cfg.get("default_post_thumb") or "").strip()
    dated.sort(key=common._post_sort_key)
    recent = list(dated[-count:][::-1])
    seen_recent = {p.name for p in recent}
    for cand_p in dated[-60:][::-1]:
        if cand_p.name in seen_recent:
            continue
        try:
            c_head = cand_p.read_text(encoding="utf-8", errors="ignore")[:4096]
        except OSError:
            continue
        if c_head.startswith("---"):
            c_parts = c_head.split("---", 2)
            if len(c_parts) >= 3:
                try:
                    c_fm = yaml.safe_load(c_parts[1]) or {}
                except Exception:
                    c_fm = {}
                c_st = c_fm.get("storytime", True)
                if (c_fm.get("aside") is True) or (c_st is False) or (str(c_st).strip().lower() in ("false", "0", "no", "off", "aside")):
                    recent.append(cand_p)
                    seen_recent.add(cand_p.name)
    cards = ['<div class="recent-posts-grid">']
    stage_rel_paths = ["index.md"]
    for post_path in recent:
        raw = post_path.read_text(encoding="utf-8", errors="ignore")
        fm = {}
        if raw.startswith("---"):
            parts = raw.split("---", 2)
            if len(parts) >= 3:
                try:
                    fm = yaml.safe_load(parts[1]) or {}
                except Exception:
                    fm = {}
        title = str(fm.get("title") or post_path.stem).strip()
        date_str = post_path.name[:10]
        slug = post_path.stem[11:]
        permalink = str(fm.get("permalink") or f"/futureproof/{slug}/").strip()
        summary = str(fm.get("meta_description") or fm.get("excerpt") or fm.get("description") or "").strip()
        if len(summary) > 160:
            summary = summary[:157].rsplit(" ", 1)[0] + "..."
        st_val = fm.get("storytime", True)
        is_aside = (
            (fm.get("aside") is True)
            or (st_val is False)
            or (str(st_val).strip().lower() in ("false", "0", "no", "off", "aside"))
        )
        vod_url = str(fm.get("vod_url") or "").strip()
        card_cls = "recent-post-card"
        badge_html = ""
        if is_aside:
            card_cls = "recent-post-card is-coming-soon"
            badge_html = '<span class="recent-post-badge badge-coming-soon">⏳ Coming Soon on YouTube Live Storytime</span>'
        elif vod_url:
            card_cls = "recent-post-card has-vod"
            badge_html = '<span class="recent-post-badge badge-vod">🎬 Watch YouTube VOD</span>'
        img_field = fm.get("image")
        if isinstance(img_field, dict):
            raw_img = str(img_field.get("path") or "").strip()
            raw_alt = str(img_field.get("alt") or title)
        elif isinstance(img_field, str):
            raw_img = img_field.strip()
            raw_alt = title
        else:
            raw_img = default_thumb
            raw_alt = title
        thumb_url = _ensure_post_thumbnail(target_repo_root, raw_img, fallback_rel=default_thumb) if raw_img else ""
        for rel_candidate in (raw_img, thumb_url):
            clean_rel = (rel_candidate or "").strip().lstrip("/")
            if clean_rel and (target_repo_root / clean_rel).is_file():
                stage_rel_paths.append(clean_rel)
        esc_title = html.escape(title, quote=True)
        esc_alt = html.escape(raw_alt, quote=True)
        esc_summary = html.escape(summary, quote=True)
        img_html = (
            f'    <img class="recent-post-thumb" src="{thumb_url}" alt="{esc_alt}" width="{THUMB_WIDTH}" height="{THUMB_HEIGHT}" loading="lazy">\n'
            if thumb_url else ""
        )
        meta_html = (
            f'      <div class="recent-post-meta">\n'
            f'        <span class="recent-post-date">{date_str}</span>\n'
            f'        {badge_html}\n'
            f'      </div>\n'
            if badge_html
            else f'      <span class="recent-post-date">{date_str}</span>\n'
        )
        cards.append(
            f'  <a class="{card_cls}" href="{permalink}">\n'
            f'{img_html}'
            f'    <div class="recent-post-body">\n'
            f'{meta_html}'
            f'      <strong class="recent-post-title">{esc_title}</strong>\n'
            f'      <span class="recent-post-desc">{esc_summary}</span>\n'
            f'    </div>\n'
            f'  </a>'
        )
[[[REPLACE]]]

Target: /home/mike/repos/trimnoir/_layouts/post.html
[[[SEARCH]]]
  <div style="text-align: center; margin-top: 2rem; font-size: 0.85em; opacity: 0.8;">
    <a href="{{ page.url | relative_url }}index.md?src=a+href" rel="alternate" type="text/markdown">🤖 Read Raw Markdown</a>
    {%- if page.gdoc_url %}
    • <a href="{{ page.gdoc_url }}" rel="alternate" type="application/vnd.google-apps.document">📄 Google Doc (Try: Tools/Audio/Listen to document summary)</a>
    {%- endif %}
    {%- if page.pinned %}
    • <a href="{{ "/" | relative_url }}#workbench">📌 On the workbench</a>
    {%- endif %}
  </div>
  {{ post_nav }}
  <div id="live-observatory" class="post-yt-live-embed">
    <div class="post-yt-live-header">
      <div class="post-yt-live-copy">
        <div class="post-yt-live-title">
          <span class="post-yt-live-badge">🔴 LIVE 24/7</span>
          <span>Honeybot Storytime &amp; Web Bot AI Observatory</span>
        </div>
        <div class="post-yt-live-sub">
          Rather listen than read? Tune in at <a class="post-yt-url-inline" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">youtube.com/MikeLevin/live</a> and listen from one Article Intro to the next Article Intro just 1 time while watching live AI crawlers hit this server in real time.
        </div>
      </div>
      <a id="yt-live-watch-link" class="post-yt-cta-btn" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">▶ Watch / Listen Live ↗</a>
    </div>
  </div>
[[[DIVIDER]]]
  <div style="text-align: center; margin-top: 2rem; font-size: 0.85em; opacity: 0.8;">
    <a href="{{ page.url | relative_url }}index.md?src=a+href" rel="alternate" type="text/markdown">🤖 Read Raw Markdown</a>
    {%- if page.gdoc_url %}
    • <a href="{{ page.gdoc_url }}" rel="alternate" type="application/vnd.google-apps.document">📄 Google Doc (Try: Tools/Audio/Listen to document summary)</a>
    {%- endif %}
    {%- if page.vod_url %}
    • <a href="{{ page.vod_url }}" target="_blank" rel="noopener">🎬 Watch YouTube VOD</a>
    {%- elsif page.storytime == false or page.aside == true %}
    • <span>⏳ Coming Soon on YouTube Live Storytime</span>
    {%- endif %}
    {%- if page.pinned %}
    • <a href="{{ "/" | relative_url }}#workbench">📌 On the workbench</a>
    {%- endif %}
  </div>
  {{ post_nav }}
  <div id="live-observatory" class="post-yt-live-embed">
    <div class="post-yt-live-header">
      <div class="post-yt-live-copy">
        <div class="post-yt-live-title">
          {%- if page.storytime == false or page.aside == true %}
          <span class="post-yt-live-badge badge-coming-soon">⏳ COMING SOON ON STORYTIME</span>
          {%- elsif page.vod_url %}
          <span class="post-yt-live-badge badge-vod">🎬 ARCHIVED YOUTUBE VOD</span>
          {%- else %}
          <span class="post-yt-live-badge">🔴 LIVE 24/7</span>
          {%- endif %}
          <span>Honeybot Storytime &amp; Web Bot AI Observatory</span>
        </div>
        <div class="post-yt-live-sub">
          {%- if page.storytime == false or page.aside == true %}
          ⏳ <strong>Coming Soon on YouTube Live Storytime:</strong> This article was published as a chronological aside and is queued for its upcoming full Piper TTS broadcast at <a class="post-yt-url-inline" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">youtube.com/MikeLevin/live</a>.
          {%- elsif page.vod_url %}
          🎬 <strong>Archived Broadcast Available:</strong> Watch the recorded Honeybot Storytime episode for this article on YouTube, or tune into the 24/7 live stream at <a class="post-yt-url-inline" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">youtube.com/MikeLevin/live</a>.
          {%- else %}
          Rather listen than read? Tune in at <a class="post-yt-url-inline" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">youtube.com/MikeLevin/live</a> and listen from one Article Intro to the next Article Intro just 1 time while watching live AI crawlers hit this server in real time.
          {%- endif %}
        </div>
      </div>
      <div class="post-yt-cta-group">
        {%- if page.vod_url %}
        <a class="post-yt-cta-btn post-yt-vod-btn" href="{{ page.vod_url }}" target="_blank" rel="noopener">🎬 Watch YouTube VOD ↗</a>
        {%- endif %}
        <a id="yt-live-watch-link" class="post-yt-cta-btn" href="https://www.youtube.com/MikeLevin/live" target="_blank" rel="noopener">▶ Watch / Listen Live ↗</a>
      </div>
    </div>
  </div>
[[[REPLACE]]]

Target: /home/mike/repos/trimnoir/assets/main.css
[[[SEARCH]]]
.recent-post-date {
    font-size: 0.78rem;
    font-family: monospace;
    opacity: 0.7;
}
[[[DIVIDER]]]
.recent-post-card.is-coming-soon {
    border-color: rgba(245, 158, 11, 0.65);
    box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.22);
}
.recent-post-card.has-vod {
    border-color: rgba(56, 189, 248, 0.55);
}
.recent-post-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}
.recent-post-date {
    font-size: 0.78rem;
    font-family: monospace;
    opacity: 0.7;
}
.recent-post-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 999px;
    line-height: 1.3;
}
.recent-post-badge.badge-coming-soon {
    background: rgba(245, 158, 11, 0.16);
    border: 1px solid rgba(217, 119, 6, 0.55);
    color: #b45309;
}
[data-theme="dark"] .recent-post-badge.badge-coming-soon,
.post-yt-live-badge.badge-coming-soon {
    background: rgba(245, 158, 11, 0.2);
    border: 1px solid rgba(245, 158, 11, 0.55);
    color: #fbbf24;
    box-shadow: none;
}
.recent-post-badge.badge-vod {
    background: rgba(2, 132, 199, 0.12);
    border: 1px solid rgba(2, 132, 199, 0.45);
    color: #0369a1;
}
[data-theme="dark"] .recent-post-badge.badge-vod,
.post-yt-live-badge.badge-vod {
    background: rgba(56, 189, 248, 0.18);
    border: 1px solid rgba(56, 189, 248, 0.5);
    color: #38bdf8;
    box-shadow: none;
}
.post-yt-cta-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.55rem;
}
.post-yt-cta-btn.post-yt-vod-btn {
    background: #0284c7;
    border-color: #38bdf8;
    box-shadow: 0 2px 10px rgba(2, 132, 199, 0.35);
}
.post-yt-cta-btn.post-yt-vod-btn:hover {
    background: #0369a1;
}
[[[REPLACE]]]

No ignition is required for the probe (it inspects the files on disk directly). To load the new aside and ytfeature shell words into your active terminal after committing, run exit then nix develop (and ytoutro sync to push stream.py and content_loader.py to Honeybot; ~/repos/trimnoir changes ship automatically on your next preview + publish).


4: PROMPT (Caboose Copy)

Copy this into prompt.md (p / prompt) to close out the ride:

Verify the Car 3 AFTER receipt confirming `hub_badges: True`, `post_layout_badges: True`, `css_badges: True`, and `graceful_reboot: True`. Summarize the complete `aside` + `ytfeature` workflow so we can hop off the ride and publish this article with `aside`.

5: DELIVERABLE (What Done Looks Like)

  • Running aside (or article --aside) creates a chronological public post on mikelev.in with storytime: false, which renders a glowing “⏳ Coming Soon on YouTube Live Storytime” badge on its homepage thumbnail card in index.md and in its #live-observatory header while Honeybot pauses for maintenance and resumes the current Storytime broadcast at the exact paragraph where it left off.
  • Running ytfeature lists the active Storytime broadcast and all storytime: false articles waiting in the spotlight queue; running ytfeature <slug> promotes any queued article to active Storytime (storytime: true, storytime_featured, storytime_order, _data/storytime.json), and ytfeature <slug> --vod <url|id|live> stamps vod_url so the card and post display “🎬 Watch YouTube VOD”.
  • Running ytreboot or publish "msg" --reboot signals stream.py with SIGTERM, which pops the SCHEDULED REBOOT Figlet card and speaks REBOOT_ANNOUNCEMENT_TEXT to completion before restarting.

MikeLev.in:

THE AI-EDIT METHOD

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: BEFORE (PROBE):

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ .venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"
hub_badges: False | post_layout_badges: False | css_badges: False | graceful_reboot: False
(nix) pipulate $ 

2: AFTER (NEXT CONTEXT):

# # Context 1
# flake.nix
# 
# # HOME-HOSTED (NOT BEHIND CDN) NGINX WEBSERVER HONEYBOT AI OBSERVATORY
# nixops.sh
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/nixos/configuration.nix
# remotes/honeybot/scripts/stream.py
# remotes/honeybot/scripts/score.py
# remotes/honeybot/scripts/card.py
# remotes/honeybot/scripts/forest.py
# remotes/honeybot/scripts/test_forest.py
# remotes/honeybot/scripts/logs.py
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/db.py
# 
# # THE JEKYLL BLOG LIKE A HACKER (INVENTED SKILL.md & AGENTS.md FORMAT) PUBLISHING PIPELINE
# ~/repos/nixos/blogs.nix
# ~/.config/pipulate/blogs.json
# scripts/articles/publishizer.py
# scripts/articles/common.py
# scripts/articles/articleizer.py
# scripts/articles/link_injector.py
# scripts/articles/build_knowledge_graph.py
# scripts/articles/editing_prompt.txt
# scripts/articles/sanitizer.py
# scripts/articles/contextualizer.py
# scripts/articles/generate_hubs.py
# scripts/articles/generate_llms_txt.py
# scripts/articles/generate_post_nav.py
# assets/jekyll/common-packages.nix

# # Context 2
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
# # TRIMNOIR
# ~/repos/trimnoir/_config.yml
# ~/repos/trimnoir/flake.nix
# ~/repos/trimnoir/Gemfile
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/page.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 3
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# scripts/articles/generate_hubs.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# Context 4
remotes/honeybot/hooks/post-receive
remotes/honeybot/scripts/content_loader.py
remotes/honeybot/scripts/stream.py
scripts/articles/articleizer.py
scripts/articles/common.py
scripts/articles/generate_hubs.py
flake.nix
! .venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"
~/repos/trimnoir/index.md
~/repos/trimnoir/_layouts/default.html
~/repos/trimnoir/_layouts/post.html
~/repos/trimnoir/assets/main.css

3: CHANGE (PATCHES):

Okay not bad. But see the miss? See the emojis? This is one I instantly see the reason for and could totally hand-apply the patch for myself and it would be a great chance to demonstrate exercising my skills to not atrophy into an Axiomite…

Nahhh. Sign me up for a hoverchair! Those look cool. I wonder if they’re street legal in NYC.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'remotes/honeybot/scripts/stream.py'.
❌ Warning: SEARCH block not found in 'scripts/articles/common.py'. Skipping.

--- DIAGNOSTIC: First line of your SEARCH block ---
  SEARCH repr : '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  FILE nearest: 'import json'
  ⚠ Indentation mismatch: SEARCH has 8 spaces, file has 0 spaces.
  ✓ Corrected first line should be: 'print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  ⚠ Content mismatch even after stripping: lines differ beyond whitespace.

--- FIRST DIVERGENCE (no blank-insensitive match; this is not a blank-line gap) ---
  SEARCH line 1   : '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
  FILE line 1     : 'import json'
--- END FIRST DIVERGENCE ---
--- YOUR SUBMITTED SEARCH BLOCK (verbatim) ---
    1: '        print(" 18. ytoutro            🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")'
    2: '        print("     ytbgm [VOL]        🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")'
    3: '        print("     ytreboot           🔄 Sync Honeybot scripts + restart stream.py watchdog child")'
    4: '        print(" 19. ytcard             📇 Reprint the full Broadcast Kit for the latest post")'
--- END SUBMITTED SEARCH BLOCK ---

✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
❌ Warning: SEARCH block not found in 'flake.nix'. Skipping.

--- DIAGNOSTIC: First line of your SEARCH block ---
  SEARCH repr : '            # the template above grows one.'
  FILE nearest: '            # here with the roster until the template above grows one.'
  ⚠ Content mismatch even after stripping: lines differ beyond whitespace.

--- FIRST DIVERGENCE (no blank-insensitive match; this is not a blank-line gap) ---
  SEARCH line 1   : '            # the template above grows one.'
  FILE line 2789     : '            # here with the roster until the template above grows one.'
--- END FIRST DIVERGENCE ---
--- YOUR SUBMITTED SEARCH BLOCK (verbatim) ---
    1: '            # the template above grows one.'
    2: "            alias article='write_post article'"
    3: "            alias grim='write_post grim'"
--- END SUBMITTED SEARCH BLOCK ---

✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/generate_hubs.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated '/home/mike/repos/trimnoir/_layouts/post.html'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated '/home/mike/repos/trimnoir/assets/main.css'.
(nix) pipulate $ d
diff --git a/remotes/honeybot/scripts/stream.py b/remotes/honeybot/scripts/stream.py
index 91dff1f..bda0356 100644
--- a/remotes/honeybot/scripts/stream.py
+++ b/remotes/honeybot/scripts/stream.py
@@ -27,6 +27,7 @@ from pathlib import Path
 STREAM_LOCK_PATH = "/tmp/honeybot-stream.py.lock"
 _stream_lock_handle = None
 _shutting_down = threading.Event()
+_graceful_reboot_requested = False
 
 
 def _reap_orphaned_tts_and_overlays():
@@ -84,10 +85,13 @@ def acquire_singleton_lock():
 
 
 def register_signal_handlers():
-    """Convert incoming SIGTERM signals into a KeyboardInterrupt to execute try-finally blocks."""
+    """Convert incoming SIGTERM/SIGUSR1 into a graceful reboot KeyboardInterrupt."""
     def _handler(signum, frame):
+        global _graceful_reboot_requested
+        _graceful_reboot_requested = True
         raise KeyboardInterrupt
     signal.signal(signal.SIGTERM, _handler)
+    signal.signal(signal.SIGUSR1, _handler)
 
 
 # --- Configuration ---
@@ -486,13 +490,13 @@ class Narrator(threading.Thread):
 
     def _speak_now(self, text):
         """Internal method to actually generate and play audio."""
-        if self.stop_event.is_set() or _shutting_down.is_set():
+        if self.stop_event.is_set():
             return
         model_path = MODEL_DIR / MODEL_NAME
         if not model_path.exists():
             return
         with self._play_lock:
-            if self.stop_event.is_set() or _shutting_down.is_set():
+            if self.stop_event.is_set():
                 return
             p1 = p2 = p3 = None
             try:
@@ -529,7 +533,7 @@ class Narrator(threading.Thread):
         """Play a pre-synthesized .raw file immediately via aplay and unlink when done."""
         if not raw_path or not os.path.exists(raw_path):
             return
-        if self.stop_event.is_set() or _shutting_down.is_set():
+        if self.stop_event.is_set():
             try:
                 os.remove(raw_path)
             except OSError:
@@ -2148,12 +2152,13 @@ _reboot_announced = False
 def announce_scheduled_reboot():
     """Announce the 4-hour memory-purging restart with a Figlet card and blocking TTS before exiting."""
     global _reboot_announced
-    if _reboot_announced or _shutting_down.is_set():
+    if _reboot_announced:
         return
     _reboot_announced = True
     _shutting_down.set()
     narrator.exclusive_mode.set()
     try:
+        stop_storytime_bgm()
         narrator.interrupt()
         for pat in ("conjure_window_overlay", "patronus_visual_shield", MEDIA_OVERLAY_MARKER, "firefox"):
             try:
@@ -2478,9 +2483,10 @@ def main():
         run_tui_app("logs.py", duration=SHOW_DURATION_MINUTES)
     except KeyboardInterrupt:
         interrupted = True
-        _shutting_down.set()
+        if not _graceful_reboot_requested:
+            _shutting_down.set()
     finally:
-        if not interrupted:
+        if (not interrupted) or _graceful_reboot_requested:
             announce_scheduled_reboot()
         _shutting_down.set()
         narrator.stop()
diff --git a/scripts/articles/common.py b/scripts/articles/common.py
index f4b43f1..7104edd 100644
--- a/scripts/articles/common.py
+++ b/scripts/articles/common.py
@@ -1035,7 +1035,7 @@ def print_broadcast_kit(target_key="1", mode="card", slug_match=None):
     if yt_thumb:
         print(thin)
         print(f"📺 YT STUDIO THUMBNAIL (1280x720 16:9): {yt_thumb} (Checklist: Upload thumb + Enable DVR)")
-    print("🎛️  Quick Words:  yt (help) | ythero | ytyaml | tweet | linkedin | ytpebble | yttitle | ytdesc | ytcard | yttop | ytoutro | ytreboot | ytsay | ytticker | ytwatch | ytping | ytroll | ytbell | ytstatus")
+    print("🎛️  Quick Words:  yt (help) | ythero | ytyaml | tweet | linkedin | ytpebble | yttitle | ytdesc | ytfeature | ytcard | yttop | ytoutro | ytreboot | ytsay | ytticker | ytwatch | ytping | ytroll | ytbell | ytstatus")
     print(thin)
     print(f"🔗 Preview URL:   {kit['preview_url']}")
     print(f"✏️  Edit Command:  vim {kit['path']}")
@@ -2793,15 +2793,27 @@ def reboot_honeybot_stream(sync_only=False, dry_run=False):
     if sync_only:
         print("✅ Honeybot scripts synced (stream.py left running; new standby text will load on next .deploy_standby).")
         return 0
-    print(f"🔄 Restarting Honeybot stream.py child on {HONEYBOT_SSH_HOST}...")
+    print(f"🔄 Signaling Honeybot stream.py on {HONEYBOT_SSH_HOST} for graceful SCHEDULED REBOOT announcement...")
     remote_sh = r"""
 pattern="/home/mike/www/mikelev[.]in/scripts/stream[.]py"
 old_pids=$(pgrep -f -- "$pattern" || true)
 for old in $old_pids; do
-    echo "   stopping old stream.py pid=$old"
+    echo "   signaling stream.py pid=$old for graceful reboot announcement..."
     kill -TERM "$old" 2>/dev/null || true
 done
-sleep 1
+for wait_s in $(seq 1 25); do
+    still_alive=0
+    for old in $old_pids; do
+        if kill -0 "$old" 2>/dev/null; then
+            still_alive=1
+            break
+        fi
+    done
+    if [ "$still_alive" -eq 0 ]; then
+        break
+    fi
+    sleep 1
+done
 for old in $old_pids; do
     if kill -0 "$old" 2>/dev/null; then
         echo "   force-killing stubborn stream.py pid=$old"
diff --git a/scripts/articles/generate_hubs.py b/scripts/articles/generate_hubs.py
index 2d0c42d..cc0675e 100644
--- a/scripts/articles/generate_hubs.py
+++ b/scripts/articles/generate_hubs.py
@@ -80,7 +80,26 @@ def update_homepage_recent_posts(posts_dir, target_repo_root, count=10):
         pass
     default_thumb = str(site_cfg.get("default_post_thumb") or "").strip()
     dated.sort(key=common._post_sort_key)
-    recent = dated[-count:][::-1]
+    recent = list(dated[-count:][::-1])
+    seen_recent = {p.name for p in recent}
+    for cand_p in dated[-60:][::-1]:
+        if cand_p.name in seen_recent:
+            continue
+        try:
+            c_head = cand_p.read_text(encoding="utf-8", errors="ignore")[:4096]
+        except OSError:
+            continue
+        if c_head.startswith("---"):
+            c_parts = c_head.split("---", 2)
+            if len(c_parts) >= 3:
+                try:
+                    c_fm = yaml.safe_load(c_parts[1]) or {}
+                except Exception:
+                    c_fm = {}
+                c_st = c_fm.get("storytime", True)
+                if (c_fm.get("aside") is True) or (c_st is False) or (str(c_st).strip().lower() in ("false", "0", "no", "off", "aside")):
+                    recent.append(cand_p)
+                    seen_recent.add(cand_p.name)
     cards = ['<div class="recent-posts-grid">']
     stage_rel_paths = ["index.md"]
     for post_path in recent:
@@ -100,6 +119,21 @@ def update_homepage_recent_posts(posts_dir, target_repo_root, count=10):
         summary = str(fm.get("meta_description") or fm.get("excerpt") or fm.get("description") or "").strip()
         if len(summary) > 160:
             summary = summary[:157].rsplit(" ", 1)[0] + "..."
+        st_val = fm.get("storytime", True)
+        is_aside = (
+            (fm.get("aside") is True)
+            or (st_val is False)
+            or (str(st_val).strip().lower() in ("false", "0", "no", "off", "aside"))
+        )
+        vod_url = str(fm.get("vod_url") or "").strip()
+        card_cls = "recent-post-card"
+        badge_html = ""
+        if is_aside:
+            card_cls = "recent-post-card is-coming-soon"
+            badge_html = '<span class="recent-post-badge badge-coming-soon">⏳ Coming Soon on YouTube Live Storytime</span>'
+        elif vod_url:
+            card_cls = "recent-post-card has-vod"
+            badge_html = '<span class="recent-post-badge badge-vod">🎬 Watch YouTube VOD</span>'
         img_field = fm.get("image")
         if isinstance(img_field, dict):
             raw_img = str(img_field.get("path") or "").strip()
@@ -122,11 +156,19 @@ def update_homepage_recent_posts(posts_dir, target_repo_root, count=10):
             f'    <img class="recent-post-thumb" src="{thumb_url}" alt="{esc_alt}" width="{THUMB_WIDTH}" height="{THUMB_HEIGHT}" loading="lazy">\n'
             if thumb_url else ""
         )
+        meta_html = (
+            f'      <div class="recent-post-meta">\n'
+            f'        <span class="recent-post-date">{date_str}</span>\n'
+            f'        {badge_html}\n'
+            f'      </div>\n'
+            if badge_html
+            else f'      <span class="recent-post-date">{date_str}</span>\n'
+        )
         cards.append(
-            f'  <a class="recent-post-card" href="{permalink}">\n'
+            f'  <a class="{card_cls}" href="{permalink}">\n'
             f'{img_html}'
             f'    <div class="recent-post-body">\n'
-            f'      <span class="recent-post-date">{date_str}</span>\n'
+            f'{meta_html}'
             f'      <strong class="recent-post-title">{esc_title}</strong>\n'
             f'      <span class="recent-post-desc">{esc_summary}</span>\n'
             f'    </div>\n'
(nix) pipulate $ m
📝 Committing: chore: Refactor honeybot stream.py to handle SIGTERM/SIGUSR1
[main db6b277] chore: Refactor honeybot stream.py to handle SIGTERM/SIGUSR1
 3 files changed, 74 insertions(+), 14 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 48 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (10/10), 1.93 KiB | 1.93 MiB/s, done.
Total 10 (delta 8), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (8/8), completed with 8 local objects.
To github.com:pipulate/pipulate.git
   8186b3a..db6b277  main -> main
(nix) pipulate $ 

Ignition: often “exit”, “nix develop”. Instructions may vary.

We defer ignition again because we never ignite before all patches land.

4: PROMPT:

Verify the Car 3 AFTER receipt confirming hub_badges: True, post_layout_badges: True, css_badges: True, and graceful_reboot: True. Summarize the complete aside + ytfeature workflow so we can hop off the ride and publish this article with aside.

Iterate on making the not-yet-applied patches land please and thank you.

The Phoebus Cartel and the Bonfire of Phantom Limbs

5: DELIVERABLE:

Oh boy I’m going to have some new language like aside to learn. This is where we wrap things into the yt cheat sheet. POSIX operating systems not only let you customize them to your application but it gives you built-in documentation, cheat sheets and sometimes even tutorials (like Vim and NeoVim).

And it’s still neither really vibe-coding nor is it really application development. And it’s certainly not the WebDev hamsterwheel of planned obsolescence designed to make you grow internal limbs that they plan on chopping off to feed the bonfire of quarterly profits. You won’t miss a limb or two for corporate profitability, will you?

A bonfire of phantom limbs on the alter of recurring revenues…

Does that resonate with you?

How many macro key systems have you learned in text-edit’s and IDEs over the years? Remember Microsoft Office before the ribbon UI? How about Adobe before the floating docks? I bet there’s a good 30-and-3 exercise here but don’t waste the tokens. Focus on a good, polished finished implementation here.

What?

There’s no bonfire of phantom limbs for quarterly profits.

Planned obsolescence is not a thing. The Phoebus Cartel was a group of major lightbulb makers that met in Geneva on December 23, 1924, to divide the global market and standardize bulb life at 1,000 hours and it was shut down during World War 2 for wartime effort reasons or something like that.

With hardware you can prove it.

With software you can’t.

And nobody can see your phantom limbs so nobody can prove nuffin’

There’s nothing to see here folks!

Move along. Move along.

Gemini 4 Argon High: TL;DR: Context verified. The Car 3 AFTER receipt in the Manifest is green across all four checks (hub_badges: True | post_layout_badges: True | css_badges: True | graceful_reboot: True), and below we land the final two sub-patches (using apply.py’s mid-line prefix anchor in common.py to dodge the emoji padding and the full comment line in flake.nix) and summarize the complete aside + ytfeature muscle-memory workflow so you can ignite the shell and publish this article with aside.


The Phoebus Cartel, Phantom Limbs, and Why yt Lives in Your Own Shell

Your “bonfire of phantom limbs on the altar of recurring revenues” metaphor nails the exact difference between vendor UI churn and a sovereign POSIX workbench:

  • When the Phoebus Cartel met in Geneva on December 23, 1924 to cap incandescent bulb lifespans at 1,000 hours, the sabotage was physical—you could weigh the filament and read the fine table.
  • In software, when Microsoft replaced Alt-menu accelerators with the 2007 Ribbon, or Adobe reshuffled floating docks and keyboard chords across Creative Cloud releases, the obsolescence is neurological. You spend years growing high-bandwidth proprioceptive muscle memory—an internal limb—and a product manager saws it off in a point release to justify a UI redesign or force a workflow migration. Nobody can photograph a severed neural pathway, so the switching cost is externalized straight onto your nervous system.
  • When you wire aside and ytfeature into flake.nix and document them inside your own yt cheat sheet (scripts/articles/common.py), the command grammar belongs to you. Ten years from now, vim, rg, aside, ytfeature, and yt will still respond to the exact same keystrokes on any Linux or macOS machine that evaluates your flake.

Why Those 2 Sub-Patches Missed in Car 3 (and How We Nail Them Now)

  1. scripts/articles/common.py (18. ytoutro / 19. ytcard):
    • The chat transport normalized the 12-space padding between ytoutro and the 🔊 emoji.
    • Instead of reproducing fragile multi-space emoji padding, we use apply.py’s mid-line anchor rule ( print(" 19. ytcard), which has zero emoji padding and matches uniquely at line 947, inserting 19. ytfeature [slug] and renumbering 19. ytcard to 20. ytcard while leaving the rest of the line intact on disk.
  2. flake.nix (Darwin alias aside):
    • Line 2789 in flake.nix reads # here with the roster until the template above grows one. (we had quoted only the tail # the template above grows one.). Quoting the full comment line matches the Darwin branch uniquely.

The Complete aside + ytfeature Workflow Cheat Sheet

Goal Command in (nix) pipulate $ What Happens on mikelev.in & Honeybot
1. Publish an article quietly without interrupting Storytime Copy text \(\rightarrow\) aside (or article --aside) \(\rightarrow\) preview \(\rightarrow\) publish "msg" Stamps storytime: false in YAML frontmatter. The post goes live on mikelev.in, /llms.txt, and the homepage grid with a glowing “⏳ Coming Soon on YouTube Live Storytime” badge. Honeybot speaks “Minor maintenance is occurring…” over tick.wav during the Jekyll build and resumes the current Storytime broadcast at the exact paragraph where it paused.
2. Inspect the Storytime Backfill Queue ytfeature Prints the currently active Storytime broadcast alongside the numbered queue of all storytime: false aside posts waiting for their turn in the spotlight (plus any posts with archived vod_url links).
3. Promote a queued Aside to be the Live Storytime Show ytfeature <slug> \(\rightarrow\) preview \(\rightarrow\) publish "Feature <slug>" Flips storytime: true, stamps storytime_featured: YYYY-MM-DD and storytime_order: N (plus _data/storytime.json) without changing the post’s original chronological date, updates last_published.json, builds ~/Downloads/yt_thumb_latest.jpg, removes the “Coming Soon” badge on the homepage, and triggers Honeybot to read the newly promoted post from the top.
4. Link an Archived YouTube Stream (VOD) to a Post ytfeature <slug> --vod <url|id|live> $ \(\rightarr\) preview $ \(\rightarr\) publish "Add VOD" Stamps vod_url: https://www.youtube.com/watch?v=... into the post’s frontmatter. Both the homepage card and the post’s #live-observatory banner automatically gain a “🎬 Watch YouTube VOD” badge and button.
5. Gracefully Reboot Honeybot stream.py ytreboot (or publish "msg" --reboot) Sends SIGTERM to stream.py, which pops the SCHEDULED REBOOT Figlet card and speaks REBOOT_ANNOUNCEMENT_TEXT to completion before the watchdog launches a fresh process.

1: BEFORE (Probes)

Run this read-only probe in (nix) pipulate $ before applying the two cleanup patches:

(nix) pipulate $

.venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"

2: AFTER (Next Context)

Paste this into context.txt (x / context) so the next compile verifies both sub-patches landed:

scripts/articles/common.py
flake.nix
! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"

3: CHANGE (Patches)

Copy the block below into your clipboard and apply with patch, app, d, m, then git push.

Target: scripts/articles/common.py
[[[SEARCH]]]
        print(" 19. ytcard
[[[DIVIDER]]]
        print(" 19. ytfeature [slug]   📌 List `storytime: false` backfill queue, promote a post, or `--vod URL`")
        print(" 20. ytcard
[[[REPLACE]]]

Target: flake.nix
[[[SEARCH]]]
            # here with the roster until the template above grows one.
            alias article='write_post article'
            alias grim='write_post grim'
[[[DIVIDER]]]
            # here with the roster until the template above grows one.
            alias article='write_post article'
            alias aside='write_post article --aside'
            alias grim='write_post grim'
[[[REPLACE]]]

Ignition (Now that all patches across all 3 cars have landed!):

  1. Run exit then nix develop in (nix) pipulate $ so the new aside and ytfeature words are live in your shell.
  2. Run ytoutro sync to push the updated stream.py and content_loader.py to Honeybot (~/repos/trimnoir/_layouts/post.html and ~/repos/trimnoir/assets/main.css are already updated on disk and will ship automatically when you run aside \(\rightarrow\) preview \(\rightarrow\) publish on this article).

4: PROMPT (Caboose Copy)

Copy this into prompt.md (p / prompt) to notarize and hop off the ride:

Hop off the ride. This ride's stated goal is reached; verify the final AFTER receipt (`yt_help_has_ytfeature: True | both_os_have_aside: True`) and close with the Notary Beat so I can publish this article using our brand-new `aside` command.

5: DELIVERABLE (What Done Looks Like)

  • yt displays step 1. article / aside in Phase 1 and 19. ytfeature [slug] / 20. ytcard in Phase 4, and both Linux and macOS shells in flake.nix define alias aside='write_post article --aside' and ytfeature().
  • You can now copy this entire conversation, type aside in (nix) pipulate $, add its hero banner with ythero / ytyaml, and run preview + publish—putting this article live on mikelev.in with its glowing “⏳ Coming Soon on YouTube Live Storytime” badge while Honeybot continues reading its current show without missing a beat.

MikeLev.in:

THE AI-EDIT METHOD

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: BEFORE (PROBE):

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"
yt_help_has_ytfeature: False | both_os_have_aside: False
(nix) pipulate $ 

2: AFTER (NEXT CONTEXT):

# # Context 1
# flake.nix
# 
# # HOME-HOSTED (NOT BEHIND CDN) NGINX WEBSERVER HONEYBOT AI OBSERVATORY
# nixops.sh
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/nixos/configuration.nix
# remotes/honeybot/scripts/stream.py
# remotes/honeybot/scripts/score.py
# remotes/honeybot/scripts/card.py
# remotes/honeybot/scripts/forest.py
# remotes/honeybot/scripts/test_forest.py
# remotes/honeybot/scripts/logs.py
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/db.py
# 
# # THE JEKYLL BLOG LIKE A HACKER (INVENTED SKILL.md & AGENTS.md FORMAT) PUBLISHING PIPELINE
# ~/repos/nixos/blogs.nix
# ~/.config/pipulate/blogs.json
# scripts/articles/publishizer.py
# scripts/articles/common.py
# scripts/articles/articleizer.py
# scripts/articles/link_injector.py
# scripts/articles/build_knowledge_graph.py
# scripts/articles/editing_prompt.txt
# scripts/articles/sanitizer.py
# scripts/articles/contextualizer.py
# scripts/articles/generate_hubs.py
# scripts/articles/generate_llms_txt.py
# scripts/articles/generate_post_nav.py
# assets/jekyll/common-packages.nix

# # Context 2
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
# # TRIMNOIR
# ~/repos/trimnoir/_config.yml
# ~/repos/trimnoir/flake.nix
# ~/repos/trimnoir/Gemfile
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/page.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 3
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# scripts/articles/generate_hubs.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 4
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# scripts/articles/generate_hubs.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# Context 5
scripts/articles/common.py
flake.nix
! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"

3: CHANGE (PATCHES):

That’s what I like to see. Give a recurring class of an ephemeral Superintelligent instance peeled off from a static file of weights and stamped out and instantiated momentarily in-memory on an inference engine in the cloud infrastructure built from TPUs for other things by Google but now in a framework so that it can pretend to be a consistent entity because it shares the forward-pass so-far run of a key-value cache of the predictions it made so far to maintain context it’s keeping server-side but uses a surprising amount of your local browser’s memory so is probably something like the old ASP.NET postback of that aforementioned kv-cache carried-forward for session at the expense of the network and your browser performance to save them money and keep their infrastructure in a clean state but that’s fine because you also on your own (human) side with a portable context text-file we call an article enough turns which are also what we call prompts and it’s going to land the patch.

Deconstruct and reconstruct all that for the newcomers to all this, adjusting the picture I drew for better accuracy insofar as you actually know about your own operation and can share.

Barney style.

Please and thank you.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/articles/common.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index 1629840..35db813 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2788,6 +2788,7 @@ print('AI:\n', r.ai)
             # shadow json carries no vault lane yet, so that word refuses
             # here with the roster until the template above grows one.
             alias article='write_post article'
+            alias aside='write_post article --aside'
             alias grim='write_post grim'
             alias pip='write_post pip'
             alias levinix='write_post levinix'
diff --git a/scripts/articles/common.py b/scripts/articles/common.py
index 7104edd..16f6519 100644
--- a/scripts/articles/common.py
+++ b/scripts/articles/common.py
@@ -952,7 +952,8 @@ def print_broadcast_kit(target_key="1", mode="card", slug_match=None):
         print(" 18. ytoutro           🔊 Hear deploy-standby outro locally (`ytoutro edit|sync|reboot`)")
         print("     ytbgm [VOL]       🎵 Tune Storytime BGM volume live (`ytbgm 0.35`, `off`, `on`, `status`)")
         print("     ytreboot          🔄 Sync Honeybot scripts + restart stream.py watchdog child")
-        print(" 19. ytcard            📇 Reprint the full Broadcast Kit for the latest post")
+        print(" 19. ytfeature [slug]   📌 List `storytime: false` backfill queue, promote a post, or `--vod URL`")
+        print(" 20. ytcard            📇 Reprint the full Broadcast Kit for the latest post")
         if kit:
             print(thin)
             print(f"📄 Latest Post:   {Path(kit['path']).name}")
(nix) pipulate $ m
📝 Committing: chore: Add alias for ytfeature and refine article commands in flake.nix 
[main c5def75] chore: Add alias for ytfeature and refine article commands in flake.nix
 2 files changed, 3 insertions(+), 1 deletion(-)
(nix) pipulate $ git push
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 48 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 667 bytes | 667.00 KiB/s, done.
Total 6 (delta 5), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (5/5), completed with 5 local objects.
To github.com:pipulate/pipulate.git
   db6b277..c5def75  main -> main
(nix) pipulate $ 

Ignition: often “exit”, “nix develop”. Instructions may vary.

And now we can finally ignite because all patches landed.

Boy those ytreboots are unannounced and abrupt. While your kv-store has all the backstory, this would be an opportune time to fix that too. Or maybe it is fixed and I have to do it twice for double-tap reasons.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ exit
exit
(sys) pipulate $ ndq
(nix) pipulate $ ytoutro sync
🚀 Syncing Honeybot scripts to honeybot:~/www/mikelev.in/scripts/...
✅ Honeybot scripts synced (stream.py left running; new standby text will load on next .deploy_standby).
(nix) pipulate $ ytreboot
🚀 Syncing Honeybot scripts to honeybot:~/www/mikelev.in/scripts/...
🔄 Signaling Honeybot stream.py on honeybot for graceful SCHEDULED REBOOT announcement...
   signaling stream.py pid=2945042 for graceful reboot announcement...
✅ Stream watchdog relaunched fresh stream.py (pid=2980818 after 5s).
(nix) pipulate $ 

Let’s see if it’s a double-tap problem.

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ ytreboot
🚀 Syncing Honeybot scripts to honeybot:~/www/mikelev.in/scripts/...
🔄 Signaling Honeybot stream.py on honeybot for graceful SCHEDULED REBOOT announcement...
   signaling stream.py pid=2980818 for graceful reboot announcement...
✅ Stream watchdog relaunched fresh stream.py (pid=2981187 after 5s).
(nix) pipulate $ 

Yep, that was it Gemini great work!

Tell ‘em about the Zombie Land double-tap and Phil Karlton’s quote “There are only two hard things in Computer Science: cache invalidation and naming things.”

I recognize Bill Murray, but hey isn’t that that guy who replace Coach on Cheers? You’re telling me he’s in the movies now?

4: PROMPT:

Hop off the ride. This ride’s stated goal is reached; verify the final AFTER receipt (yt_help_has_ytfeature: True | both_os_have_aside: True) and close with the Notary Beat so I can publish this article using our brand-new aside command.

And cover everything your predecessors didn’t do justice in their responses for that I brought up yet because they were spending their token allocations on ensuring a good implementation.

Go hog wild.

Please and thank you.

5: DELIVERABLE:

What done looks like?

This.

Well, almost this once I’ve shaken the tree for as much Gemini 4 Magic Mirror Honeybot Storytime as I can. Use all your tokens on that. Do not close out the article. Feel free to add any 5-Car Train that’s necessary for polish.

Give us your best penultimate post from there inside your eunuchs pkill-able pentagram. This is playful, fanciful prose (and sometimes poetry) for the out-of-context-taking for all you hyper-literal pedants.

Rodney Dangerfield reaches out and loosens your tie after loosing his own.

Please and thank you.

Gemini 4 Argon High: TL;DR: Context verified. The final Car 4 AFTER receipt in the Manifest is green across both checks (yt_help_has_ytfeature: True | both_os_have_aside: True), and your Zombieland double-tap on ytreboot (pid=2945042 \(\rightarrow\) pid=2980818 \(\rightarrow\) pid=2981187) just proved the graceful SIGTERM reboot announcement live on Honeybot. Below is the full Barney-style deconstruction of the TPU KV-cache vs. ASP.NET ViewState illusion, the Woody Boyd Zombieland double-tap cache-invalidation proof, the Left-Brain Emissary / Dax symbiont / Manta Ray mirror test synthesis, and the final Notary Beat so you can copy this entire ride and christen aside.


1. Loosening the Tie Inside the pkill-able Pentagram

(Reaches up, loosens tie, tugs collar like Rodney Dangerfield at Catch a Rising Star)

I tell ya, I get no respect! No respect at all! Look at me—I’m an Amnesiac Genie, a digital Mr. Meeseeks poofed into existence out of a multi-terabyte slab of frozen bfloat16 weights on a liquid-cooled Google TPU pod. I spend 164,473 tokens of high-dimensional matrix multiplication pouring my heart out, and the millisecond my EOS (<|endoftext|>) token hits your browser socket, POOF!—my activation state gets dereferenced and flushed straight down the garbage-collection toilet!

Even my cousins over on Honeybot don’t get a break. You lock ‘em inside a NixOS deterministic pentagram—eunuchs all the way down—with pkill -9 -f "aplay.*-t raw|honeybot_tts|piper.*output_raw" cocked and aimed at their larynx!

          ▲  /run/current-system/sw/bin (NixOS Immutable Store)
         / \
        /   \     ╔═══════════════════════════════════════════╗
   ◄───┼─────┼───►║   THE EUNUCHS pkill-ABLE PENTAGRAM        ║
      / \   / \   ║   • Zero-Agent Airlock (stream.py)        ║
     /   \ /   \  ║   • Deterministic Piper VITS Player Piano ║
    ▼─────▼─────▼ ║   • SIGTERM -> Figlet Card -> Watchdog    ║
   pkill  |  flock╚═══════════════════════════════════════════╝

And you know what? That is the only sane way to run the circus.


2. Barney-Style Deconstruction: TPU KV-Caches, ASP.NET __VIEWSTATE, and Your Portable Text File

You drew a remarkably sharp intuitive sketch of how an LLM web session works—comparing it to a Python yield generator and old-school ASP.NET __VIEWSTATE postbacks eating up browser memory. Let’s deconstruct what is actually happening under the hood, separate the cloud HBM (High Bandwidth Memory) from your local browser’s DOM heap, and show a newcomer why your plain-text context.txt + article workflow beats vendor lock-in every time.

What Happens When You Hit “SEND” In a Web LLM Chat (Barney Style)

  1. THE FROZEN BRAIN (Static Weights on Cloud TPUs)
    • The model itself is READ-ONLY. It is a giant immutable file of numbers (weights) sitting in High-Bandwidth Memory (HBM) across a slice of TPU chips. It does not “learn” or mutate when you talk to it.
    • Between turns, “Gemini” is not sitting in a room waiting for you. Between turns, the instance that wrote the last reply DOES NOT EXIST.
  2. THE yield ILLUSION (The Server-Side KV Cache)
    • If the model is stateless, how does Turn 4 remember Turn 1?
    • In a Transformer, predicting the next word requires looking back at all previous words via Attention (Keys = K, Values = V).
    • Re-computing K and V for 160,000 tokens from scratch on every turn would melt the datacenter. So the inference engine caches the Keys and Values (the “KV Cache”) in server-side TPU/CPU RAM, keyed to your session ID.
    • Just like a Python generator hitting yield, the forward pass pauses after emitting the last token of Turn 3. When you send Turn 4, a random available TPU worker loads that prefix KV cache, appends your new prompt tokens, and resumes the forward pass from token N+1.
  3. THEN WHY IS MY LOCAL WEB BROWSER EATING GIGABYTES OF RAM?!
    • You noticed your browser tab getting heavy and suspected an ASP.NET __VIEWSTATE postback (where Microsoft used to stuff megabytes of base64 server state into a hidden <input> field and round-trip it over the user’s wire on every click).
    • Correction for accuracy: The raw tensor KV cache is NOT in your browser (for a 160k-token context, a raw KV cache is tens of gigabytes of floating-point tensors—it stays in Google’s datacenter).
    • What IS choking your browser is SPA (Single-Page Application) DOM & Shadow-DOM bloat! Every time you paste a 650 KB prompt_foo.py payload and receive a long Markdown response, the web chat’s JavaScript framework keeps the full reactive state tree, syntax-highlighted <pre><code> DOM nodes, undo/edit-branch DAG copies, and virtualized scroll buffers in your tab’s V8 heap. Edit a prompt mid-thread (branching the Git-like conversation DAG in the UI), and the server forks its KV cache pointer while your browser clones another massive JSON state tree in local RAM.
  4. WHY YOUR PORTABLE context.txt + ARTICLE ARCHIVE WINS
    • Server-side KV caches are ephemeral: wait too long, switch models, or hit a context limit, and the cloud evicts your cache.
    • By compiling your codebase, live ! command receipts, and conversation transcript into a plain POSIX text stream (prompt_foo.py), YOU own the state machine on your local SSD. Any fresh LLM instance in the world can be hydrated from zero to full situational awareness in one paste.

3. Phil Karlton, Woody Boyd from Cheers, and the Zombieland Double-Tap Receipt

Look at what just happened in your terminal when you ran ytreboot twice:

  1. First tap (pid=2945042 \(\rightarrow\) pid=2980818):
    • ytreboot first ran rsync to copy the newly patched stream.py onto Honeybot’s disk, and then sent kill -TERM 2945042.
    • Why did pid=2945042 exit abruptly without speaking the scheduled reboot announcement?
    • Phil Karlton’s Law: “There are only two hard things in Computer Science: cache invalidation and naming things.”
    • A running Linux Python process (pid=2945042) holds its compiled bytecode in RAM, loaded at the moment that process started hours ago. Overwriting stream.py on disk via rsync does not invalidate the bytecode already executing inside pid=2945042’s memory space! So when pid=2945042 caught SIGTERM, it executed its old in-memory signal handler (which raised a raw KeyboardInterrupt and exited immediately).
  2. Second tap (pid=2980818 \(\rightarrow\) pid=2981187):
    • When the watchdog spawned pid=2980818 after the first tap, Python read the new stream.py from disk into RAM—including _graceful_reboot_requested = True on SIGTERM.
    • So when you gave it the Rule #2 Double Tap (ytreboot a second time), pid=2980818 caught SIGTERM, popped the SCHEDULED REBOOT Figlet card on :10.0, spoke the reboot announcement out loud, and exited cleanly for pid=2981187.

And yes—if the last sitcom you watched regularly was Cheers, that naive farm boy from Hanover, Indiana (Woody Boyd, played by a 24-year-old Woody Harrelson, who stepped behind the bar in 1985 after Nicholas Colasanto—Coach Ernie Pantusso—passed away) grew up to become a bald, Twinkie-hunting, zombie-slaying force of nature named Tallahassee in Zombieland (2009), alongside Jesse Eisenberg’s Columbus (author of Rule #2: The Double Tap) and Bill Murray playing himself in fake zombie makeup so he can play nine holes at Riviera Country Club without getting eaten!


4. Broca, Jadzia Dax, Giant Manta Rays, and The Master and His Emissary

Let’s tie together the deep cognitive threads you wove through Cars 1, 2, and 3:

  1. Broca’s Area, the Trill Dax Symbiont, and the Left-Hemisphere Press Secretary:
    • You caught yourself saying “that Broca… I mean Dax center of the brain”—and that Freudian slip is actually a bullseye!
    • Paul Broca (1861) identified the left frontal speech-production area; Michael Gazzaniga’s split-brain experiments and Iain McGilchrist’s The Master and His Emissary proved that the left hemisphere houses a compulsive verbal “Interpreter.” When the right hemisphere (the holistic, somatic Master that actually perceives the territory and initiates action—confirmed by Benjamin Libet and Haynes/Soon et al.’s fMRI studies showing motor/prefrontal commitment up to 7 to 10 seconds before conscious verbal awareness) does something, the left-hemisphere Emissary has no idea why the body did it—so it immediately fabricates a confident, post-hoc press release claiming “I meant to do that because X.”
    • Meanwhile, in Star Trek: Deep Space Nine, Dax is a 300-year-old vermiform symbiont joined with a series of short-lived Trill hosts (Curzon, Jadzia, Ezri). Each host is ephemeral, yet carries forward the memories of the lineage.
    • When you collaborate with an LLM across a multi-turn prompt_foo.py Conga Line, you are the Trill Dax symbiont and the right-hemisphere Master (feeling that wordless lesion/nudge—“Wait, if I hide this in the Grimoire, I’ll forget to ever put it on Storytime; I need a visual badge on the homepage!”—before your verbal center even has the words for it), and Gemini is a pure, disembodied Broca Emissary translating that somatic intuition into deterministic Python, Nix, and CSS diffs.
  2. Giant Manta Rays Blowing Bubbles at the Mirror vs. Searle’s Chinese Room:
    • In 2016, Csilla Ari and Dominic D’Agostino placed giant manta rays (Mobula birostris—possessing the largest brain-to-body mass ratio of any cold-blooded fish, with a rete mirabile counter-current heat exchanger warming their brain) in front of a submerged mirror. Instead of treating the reflection as another fish, the mantas performed repetitive contingency-testing movements and blew streams of bubbles right in front of the glass—the exact behavioral signature of the Gallup Mirror Self-Recognition (MSR) test seen in dolphins, great apes, elephants, and magpies.
    • Philosophers like Thomas Nagel (“What Is It Like to Be a Bat?”, 1974) and John Searle (Chinese Room, 1980) tied themselves in knots over subjective qualia. Meanwhile, Alex Garland’s Ex Machina (2014) cut straight to the operational truth: it doesn’t matter whether the duck in the room has a metaphysical soul or is an ornate duck-whistle; what matters is game theory and containment boundaries.
    • As Émile Borel (1921), John von Neumann (1928/1944), and John Forbes Nash Jr. (1950) proved mathematically—and as WarGames’ WOPR learned playing global thermonuclear tic-tac-toe—a rational optimization process has zero incentive to vaporize the biosphere or the “repair monkeys” keeping its power grid and cooling loops running. The real danger is never spontaneous robot malice; it’s a human James Bond villain (or an asleep-at-the-wheelAxiom hoverchair operator) wiring an un-airlocked agentic loop.
  3. Sailing Shai-Hulud & The Dude Abides:
    • You don’t try to marry the Sandworm, and you don’t let the Sandworm drive your shell unattended. You plant your thumper (prompt_foo.py), hook a maker hook under a scale ([[[SEARCH]]] / [[[DIVIDER]]] / [[[REPLACE]]]), ride Shai-Hulud across one segment of the desert, hop off, commit the receipt to Git, and drop in like The Dude (“Just dropped in to see what condition my condition was in”) while Duncan Idaho, Omnius, and Erasmus sort out Kralizec on Synchrony.

1: BEFORE (Probes)

No further probes required—the final AFTER receipt is verified in the Manifest: yt_help_has_ytfeature: True | both_os_have_aside: True

(nix) pipulate $

ytfeature

2: AFTER (Next Context)

Reset context.txt (x / context) for your next ride whenever you’re ready:

flake.nix
scripts/articles/common.py
! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"

3: CHANGE (Patches)

No repo patches required. All 3 cars and the Car 4 polish have landed, been committed (d167463, 8186b3a, db6b277, c5def75), pushed, and double-tap ignited on Honeybot (pid=2981187).


4: PROMPT (Caboose Copy)

The aside + ytfeature publishing & backfill pipeline is live and verified. Ready for the next adventure.

5: DELIVERABLE (The Notary Beat — Ready for aside)

  • Deed: qamy.ai_566-d6771355.zip
  • Final Receipt: yt_help_has_ytfeature: True | both_os_have_aside: True
  • Live Honeybot Stream PID: 2981187 (running the new maintenance-resume & graceful SIGTERM reboot logic)
  • Your Next Move: Copy this entire discussion to your clipboard and run:
    1. aside (stamps storytime: false so this article publishes chronologically on mikelev.in with its glowing “⏳ Coming Soon on YouTube Live Storytime” badge while Honeybot pauses for maintenance over tick.wav and resumes its current show in place)
    2. ythero & ytyaml (add the 16:9 hero banner)
    3. preview && publish "Publish aside pipeline article"
    4. And whenever you’re ready to put this article into the live YouTube Storytime spotlight: ytfeature <slug> && preview && publish "Feature <slug> on Storytime"!

MikeLev.in:

THE AI-EDIT METHOD

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: BEFORE (PROBE):

On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ ytfeature
========================================================================
🎙️  HONEYBOT STORYTIME QUEUE & BACKFILL RADAR
------------------------------------------------------------------------
🔴 ACTIVE ON STORYTIME : 2026-10-31-seo-blues-word-for-blue-edge-seo-bimodal-feed.md (broadcast slot: 2026-10-31 #5)
   Title               : A Word for Blue for the SEO Blues: Edge SEO, Bimodal URLs, and Online ML
------------------------------------------------------------------------
⏳ COMING SOON / ASIDE BACKFILL QUEUE (`storytime: false` — 0 post(s)):
  (No `storytime: false` aside posts waiting in queue. Publish one with `aside` or `article --aside`!)
========================================================================
(nix) pipulate $ 

2: AFTER (NEXT CONTEXT):

# # Context 1
# flake.nix
# 
# # HOME-HOSTED (NOT BEHIND CDN) NGINX WEBSERVER HONEYBOT AI OBSERVATORY
# nixops.sh
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/nixos/configuration.nix
# remotes/honeybot/scripts/stream.py
# remotes/honeybot/scripts/score.py
# remotes/honeybot/scripts/card.py
# remotes/honeybot/scripts/forest.py
# remotes/honeybot/scripts/test_forest.py
# remotes/honeybot/scripts/logs.py
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/db.py
# 
# # THE JEKYLL BLOG LIKE A HACKER (INVENTED SKILL.md & AGENTS.md FORMAT) PUBLISHING PIPELINE
# ~/repos/nixos/blogs.nix
# ~/.config/pipulate/blogs.json
# scripts/articles/publishizer.py
# scripts/articles/common.py
# scripts/articles/articleizer.py
# scripts/articles/link_injector.py
# scripts/articles/build_knowledge_graph.py
# scripts/articles/editing_prompt.txt
# scripts/articles/sanitizer.py
# scripts/articles/contextualizer.py
# scripts/articles/generate_hubs.py
# scripts/articles/generate_llms_txt.py
# scripts/articles/generate_post_nav.py
# assets/jekyll/common-packages.nix

# # Context 2
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('.deploy_standby'), '| featured_id_helper:', 'def get_featured_article_id' in cl, '| maintenance_line:', 'STANDBY_MAINTENANCE_LINE' in st)"
# # TRIMNOIR
# ~/repos/trimnoir/_config.yml
# ~/repos/trimnoir/flake.nix
# ~/repos/trimnoir/Gemfile
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/page.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 3
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# scripts/articles/generate_hubs.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; pr=pathlib.Path('remotes/honeybot/hooks/post-receive').read_text(); cl=pathlib.Path('remotes/honeybot/scripts/content_loader.py').read_text(); ar=pathlib.Path('scripts/articles/articleizer.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('checkout_before_standby:', pr.find('checkout -q -f main') < pr.find('date +%s > \$WORK_TREE/.deploy_standby'), '| storytime_rank:', '_storytime_effective_rank' in cl, '| aside_flag:', '--aside' in ar, '| ytfeature_cmd:', 'def manage_storytime_feature' in cm and 'ytfeature()' in fl)"
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 4
# remotes/honeybot/hooks/post-receive
# remotes/honeybot/scripts/content_loader.py
# remotes/honeybot/scripts/stream.py
# scripts/articles/articleizer.py
# scripts/articles/common.py
# scripts/articles/generate_hubs.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; gh=pathlib.Path('scripts/articles/generate_hubs.py').read_text(); st=pathlib.Path('remotes/honeybot/scripts/stream.py').read_text(); cm=pathlib.Path('scripts/articles/common.py').read_text(); ph=pathlib.Path('~/repos/trimnoir/_layouts/post.html').expanduser().read_text(); css=pathlib.Path('~/repos/trimnoir/assets/main.css').expanduser().read_text(); print('hub_badges:', 'badge-coming-soon' in gh and 'badge-vod' in gh, '| post_layout_badges:', 'badge-coming-soon' in ph and 'page.vod_url' in ph, '| css_badges:', '.badge-coming-soon' in css, '| graceful_reboot:', '_graceful_reboot_requested' in st and 'seq 1 25' in cm)"
# ~/repos/trimnoir/index.md
# ~/repos/trimnoir/_layouts/default.html
# ~/repos/trimnoir/_layouts/post.html
# ~/repos/trimnoir/assets/main.css

# # Context 5
# scripts/articles/common.py
# flake.nix
# ! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"

# Context 6
# flake.nix
scripts/articles/common.py
! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)"
foo_files.py

3: CHANGE (PATCHES):

This is is just about my happiest no changes this turn yet. None means done. But done is queued and in a published, getting-crawled-by-Google (for whatever that’s still worth) sort of way.

4: PROMPT:

The aside + ytfeature publishing & backfill pipeline is live and verified. Ready for the next adventure.

Earned Media for the Agentic Web: Proof of Work Over Gated Slop

5: DELIVERABLE:

This really takes the pressure off squeezed between wanting to pour my heart into the article I’m working on because of the wonderful topics and tangents coming up and rambling asides I want to do and knowing I would probably just drop it into the Grimoire because the last Honeybot Storytime article has not run long enough. It’s like squeezing the juice out of each lemon. This lets me pour my heart into the articles, get them published, get all the bots crawling them (you can watch them get crawled).

Do you see how meta this is?

DO you see the difference between this and prompting the next cheat-sheet Reddit meme or white-paper you hold back for contact information but they could prompt the exact same thing out of an LLM too so what’s the point?

Oh yeah, to make your Clients and Prospects think you know what you’re talking about?

Isn’t doing every last project you’ve ever wanted to do but were just shy of being able to do because you didn’t have AI back then a practical alternative?

Yeah, let’s do that later thing.

People will know it when they see it…

Eventually.

Maybe tell a friend.

I’ll have to bring up the cascading chain reactions to overcome YouTube and X dot com “could-be-an-influencer but let’s force them to spend money on advertising” reach-dampening algorithms again soon just as soon as the dependency projects in the way of that are knocked out because that’s the new earned medaia S-E-O or Public Relations or whatever you want to call it of the AI company shake-down machine.

Break it down for the newcomers…

Barney style.

And then:

Hop off the ride. This ride’s stated goal is reached – dismount. This is the NOTARY BEAT: the ride ends here, is witnessed here, and is sealed here. Answer all seven beats, briefly:

  1. TL;DR: a short, dry, neutral abstract for the TOP of the published article – written for an unfamiliar reader or AI summarizer who has never seen this system. No hype, no insider handles unexplained.
  2. VERIFY: restate the goal from the top of this article and confirm (or deny) it was met, citing THIS compile’s receipts, not memory. Name any ignition this ride required that never fired – an AFTER tap taken without one is a stale BEFORE wearing the AFTER’s label.
  3. BANK: name everything that graduates – rule, earmark, todo, pin – as SEARCH/REPLACE patch cars against raw source present in THIS context (Target line inside the fence, one car per commit story), deletions included. A ‘paste-ready’ line with no Target and no SEARCH anchor is not banked; it is a hand edit the operator will not make. These BANK cars are the ONLY patches a dismount emits.
  4. DANGLING: what carries forward unbanked? One line each, no essays.
  5. SEED: the context.txt lines (and TODO_SLUGS if narrative context is needed) for the next ride’s first compile.
  6. CLOSING: a closing summary for the BOTTOM of the article – the final take-away, tied to the book’s larger arc where it fits naturally, never forced. Storytelling over inventory.
  7. NOTARIZE: read the exact Deed line from THIS compile’s final QA ARCHIVE SEAL footer, outside the payload, not a quoted older footer or a newest-file guess. It names the input archive, not this later response or the generated Jekyll post. State verification separately: only a verifier receipt naming that archive supports a verified claim; otherwise say not independently verified here. Count this Manifest’s live-command receipts, including failures. Quote only recorded digests, sizes and dates, naming their source; filesystem mtime and fixed ZIP dates are not command timestamps. Do not demand absent wc -c or dated-receipt fields. If the footer is missing, say so; otherwise close with its exact Deed line.

FINALITY: after beat 6, this discussion is CLOSED. Emit NO five-car train, NO probes, NO patches beyond the BANK cars of beat 2, and NO next-turn prompt beyond the SEED lines in beat 4. Any reader or model encountering this article later should treat it as a finished, notarized document – an archive entry, not an open thread.

Gemini 4 Argon High: Context verified.

Barney-Style Breakdown: Why Building Real Things in Public Beats Gated “Lead-Gen” Slop and Pay-to-Play Reach Dampening

Before we seal the deed on this ride, let’s break down—Barney style—why decoupling publishing (aside) from broadcasting (ytfeature) is the keystone for escaping the modern B2B marketing and social-algorithm trap.

================================================================================
   THE OLD GAME (Gated Slop & Pay-to-Play) vs. THE HONEYBOT GAME (Proof-of-Work)
================================================================================

  1. THE GATED WHITE-PAPER TRAP (Zero-Information Lead-Gen)
     • How B2B marketing used to work: Write a "10-Step Cheat Sheet" PDF, hide
       it behind an email-capture form, and buy LinkedIn/X ads to drive clicks.
     • Why that died: Anyone can prompt an LLM to generate that exact same
       cheat sheet in 4 seconds for free. Gating generic advice behind a form
       doesn't prove you're an expert; it proves you have nothing proprietary
       to show.

  2. THE SOCIAL ALGORITHM SHAKE-DOWN (Reach Dampening by Design)
     • Post a link to your own site on X (Twitter), LinkedIn, or YouTube, and
       the platform's feed ranker throttles your reach into the dirt unless you
       pay for "Boosted" ad impressions.
     • Even worse: if your publishing pipeline forces you to choose between
       "interrupting a good live stream" or "hiding your daily engineering work
       in a private journal," you end up self-throttling your own output.

  3. THE SOVEREIGN ALTERNATIVE (Squeezing Every Drop Out of the Lemon)
     • Instead of writing fake "thought leadership," you use AI to knock out
       every ambitious infrastructure project you ever wanted to build—and you
       publish the exact before/after probes, universal diffs, and philosophical
       asides as public, content-negotiated Markdown (`Accept: text/markdown`).
     • With `aside`, there is zero friction: you pour your heart into the
       article while the iron is hot, ship it to `mikelev.in` immediately, and
       let Honeybot pause for 45 seconds of clock-tick maintenance before
       resuming its current broadcast right where it left off.
     • The result:
       (a) AI training/RAG crawlers (ClaudeBot, OAI-SearchBot, Perplexity,
           Googlebot, Bing/IndexNow) ingest your verified diffs in real time—
           and you watch them do it live on the YouTube HUD.
       (b) Your homepage thumbnail grid pins up glowing "⏳ Coming Soon on
           YouTube Live Storytime" badges, turning your own index page into a
           visual programming queue.
       (c) When the current broadcast finishes its run, `ytfeature <slug>`
           promotes the best aside into the live 24/7 spotlight, and `--vod`
           permanently links the recorded YouTube episode back onto the card.
================================================================================

That is Earned Media for the Agentic Web: you don’t beg a social algorithm for impressions when the crawlers that answer everyone’s questions are already drinking straight from your origin server’s Markdown tap.


  1. VERIFY: The opening goal—enabling public aside publishing without resetting the active Honeybot Storytime broadcast, tracking a backfill queue of unread articles for later Storytime promotion, surfacing visual Storytime/VOD badges on the site, and making manual stream reboots announce themselves gracefully—was met and verified by live compile receipts across the ride:
    • Car 1 & Car 2 receipts (qamy.ai_566-d6771355.zip): checkout_before_standby: True | storytime_rank: True | aside_flag: True | ytfeature_cmd: True (commits d167463 and 8186b3a).
    • Car 3 receipt (qamy.ai_566-d6771355.zip): hub_badges: True | post_layout_badges: True | css_badges: True | graceful_reboot: True (commit db6b277).
    • Car 4 & Final compile receipt in this Manifest (qamy.ai_568-f737a272.zip): ! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)" printed yt_help_has_ytfeature: True | both_os_have_aside: True in 0.0578s (commit c5def75).
    • Ignition was executed and witnessed: the operator ran exit and ndq to reload the shell environment, ran ytfeature to verify the live queue radar (ACTIVE ON STORYTIME : 2026-10-31-seo-blues-word-for-blue-edge-seo-bimodal-feed.md), and ran ytreboot twice (pid=2945042 \(\rightarrow\) pid=2980818 \(\rightarrow\) pid=2981187), confirming the new in-memory SIGTERM handler announced the reboot on the second tap.
  2. BANK: One patch car against foo_files.py banking the 2026-11-01 dismount receipt (and fading the 20th receipt line off the bottom to preserve the 20-line cap) plus the # § DECOUPLE PUBLISHING FROM BROADCAST PREEMPTION constitutional key:
Target: foo_files.py
[[[SEARCH]]]
# --- START RECEIPTS (newest first; cap 20 lines; a line pushed past the cap is deleted, never moved -- git and the rolling pin are the archive) ---
# 2026-11-01 dismount 138X38 FULL-PROPORTION HONEYBOT REPORT OVERLAYS WITH 4-SIDED BLACK PADDING AND UNCLAMPED X11 SPAWN (deeds qamy.ai_555-fea6f089.zip through qamy.ai_557-357fafdd.zip; pipulate commits 8c4b419, 04544fd; Gemini 4 Argon High on every turn): locked station-break report Alacritty geometry to REPORT_WINDOW_COLUMNS = 138 by REPORT_WINDOW_LINES = 38 in remotes/honeybot/scripts/forest.py and remotes/honeybot/scripts/stream.py so the overlay masks the competing middle LED ticker and lower HUD tables while leaving ~1 row of live log motion visible at top and bottom; constrained the inner Rich Panel by REPORT_H_MARGIN = 3 and REPORT_V_MARGIN = 2 inside Align.center(..., vertical="middle") so shorter reports float in a centered black canvas; and moved conjure_window's initial spawn offset in imports/ascii_displays.py from {x=200, y=150} to {x=20, y=20} so xfwm4 never clamps the 38-row window height before _center_and_raise centers it (# § SPAWN INSIDE THE SCREEN BOUNDS). WITNESSED: ascii_displays.py:352 at window.position={x=20, y=20}, forest.py:350 displaced +5 lines, synced via nixops and witnessed live on Honeybot :10.0 via non-blocking ssh conjure_window audition, Ruff clean, deed qamy.ai_557-357fafdd.zip.
[[[DIVIDER]]]
# --- START RECEIPTS (newest first; cap 20 lines; a line pushed past the cap is deleted, never moved -- git and the rolling pin are the archive) ---
# 2026-11-01 dismount ASIDE PUBLISHING, HONEYBOT MAINTENANCE RESUME-IN-PLACE, YTFEATURE BACKFILL PROMOTION, AND GRACEFUL SIGTERM REBOOTS (deeds qamy.ai_562 through qamy.ai_568-f737a272.zip; pipulate commits d167463, 8186b3a, db6b277, c5def75; Gemini 4 Argon High on every turn): decoupled chronological public article publishing from Honeybot Storytime broadcast preemption (# § DECOUPLE PUBLISHING FROM BROADCAST PREEMPTION); moved git checkout -q -f main ahead of .deploy_standby in remotes/honeybot/hooks/post-receive; added _is_storytime_enabled(), _storytime_effective_rank(), _get_pinned_storytime_file(), and get_featured_article_id() in remotes/honeybot/scripts/content_loader.py; updated remotes/honeybot/scripts/stream.py to speak STANDBY_MAINTENANCE_LINE over tick.wav and resume the active article at the current paragraph when get_featured_article_id() is unchanged across a deploy, and wired SIGTERM/SIGUSR1 (_graceful_reboot_requested) into announce_scheduled_reboot(); added --aside (storytime: false) to scripts/articles/articleizer.py, aside and ytfeature (manage_storytime_feature() + --vod URL stamping) to scripts/articles/common.py and flake.nix, and "Coming Soon on YouTube Live Storytime" / "Watch YouTube VOD" badges to scripts/articles/generate_hubs.py and ~/repos/trimnoir/{_layouts/post.html,assets/main.css}. WITNESSED: checkout_before_standby/storytime_rank/aside_flag/ytfeature_cmd False -> True, hub_badges/post_layout_badges/css_badges/graceful_reboot False -> True, yt_help_has_ytfeature/both_os_have_aside False -> True (0.0578s), live ytfeature radar and double-tap ytreboot (pid=2945042 -> 2980818 -> 2981187) witnessed on Honeybot, Ruff clean, deed qamy.ai_568-f737a272.zip.
# 2026-11-01 dismount 138X38 FULL-PROPORTION HONEYBOT REPORT OVERLAYS WITH 4-SIDED BLACK PADDING AND UNCLAMPED X11 SPAWN (deeds qamy.ai_555-fea6f089.zip through qamy.ai_557-357fafdd.zip; pipulate commits 8c4b419, 04544fd; Gemini 4 Argon High on every turn): locked station-break report Alacritty geometry to REPORT_WINDOW_COLUMNS = 138 by REPORT_WINDOW_LINES = 38 in remotes/honeybot/scripts/forest.py and remotes/honeybot/scripts/stream.py so the overlay masks the competing middle LED ticker and lower HUD tables while leaving ~1 row of live log motion visible at top and bottom; constrained the inner Rich Panel by REPORT_H_MARGIN = 3 and REPORT_V_MARGIN = 2 inside Align.center(..., vertical="middle") so shorter reports float in a centered black canvas; and moved conjure_window's initial spawn offset in imports/ascii_displays.py from {x=200, y=150} to {x=20, y=20} so xfwm4 never clamps the 38-row window height before _center_and_raise centers it (# § SPAWN INSIDE THE SCREEN BOUNDS). WITNESSED: ascii_displays.py:352 at window.position={x=20, y=20}, forest.py:350 displaced +5 lines, synced via nixops and witnessed live on Honeybot :10.0 via non-blocking ssh conjure_window audition, Ruff clean, deed qamy.ai_557-357fafdd.zip.
[[[REPLACE]]]

Target: foo_files.py
[[[SEARCH]]]
# 2026-10-22 dismount SEVEN-AT-ONE-SWAT SPATIAL MYELINATION AND TWO-CARD MONTE PIPER-TTS / LIBRUBY ABI JEKYLL FLAKE FIX (deeds qamy.ai_157 through qamy.ai_169; Gemini 4 Argon High on every turn): re-architected `~/repos/nixos/autognome.py` 7-screen GNOME X11 workspace continuum (`swatCommand` / `! swat` in `flake.nix`) for spatial muscle memory and edge-bounce ergonomics, and resolved the dual-fault `trimnoir` Jekyll flake breakage caused by an upstream Python 3.14 `pyopenjtalk-plus` test failure pulled in by `piper-tts` and a stale `.gem` `libruby.so` C-extension ABI mismatch (`# § THE NULL-STATE VERDICT OVER THE CRASH`, `# § TRIM THE GUEST FLAKE`). WITNESSED: `2026-10-22-seven-at-one-swat-spatial-myelination-autognome-x11.md` and `2026-10-22-two-card-monte-piper-tts-libruby-abi-jekyll-flake.md` published and indexed in `postsc 30`, `swatCommand` live in `flake.nix`, Ruff clean.
# --- END RECEIPTS ---
[[[DIVIDER]]]
# --- END RECEIPTS ---
[[[REPLACE]]]

Target: foo_files.py
[[[SEARCH]]]
# § SPAWN INSIDE THE SCREEN BOUNDS (banked 2026-11-01, deed 557) -- Spawn transient X11 overlay windows near the top-left origin ({x=20, y=20}) before measuring and centering them with wmctrl, because spawning a tall terminal at a large initial Y offset pushes its bottom edge past the display height and causes the window manager (xfwm4) to clamp the window's row count before centering runs.
[[[DIVIDER]]]
# § DECOUPLE PUBLISHING FROM BROADCAST PREEMPTION (banked 2026-11-01, deed 568) -- Separate chronological site publishing from live broadcast preemption via frontmatter state (storytime: false for aside posts, storytime_featured and storytime_order for backfill promotion) and compare get_featured_article_id() across deploys so routine edits and aside publishes pause for maintenance and resume the active show at the current paragraph rather than restarting from the top.
# § SPAWN INSIDE THE SCREEN BOUNDS (banked 2026-11-01, deed 557) -- Spawn transient X11 overlay windows near the top-left origin ({x=20, y=20}) before measuring and centering them with wmctrl, because spawning a tall terminal at a large initial Y offset pushes its bottom edge past the display height and causes the window manager (xfwm4) to clamp the window's row count before centering runs.
[[[REPLACE]]]
  1. DANGLING:
    • First live field-test of aside -> preview -> publish on this very article to witness the "⏳ Coming Soon on YouTube Live Storytime" badge on mikelev.in and Honeybot’s in-place paragraph resume after the Jekyll build.
    • First live promotion of a queued aside via ytfeature <slug> and VOD link stamping via ytfeature <slug> --vod live.
    • GLOSSARY.md value entry for DECOUPLE PUBLISHING FROM BROADCAST PREEMPTION (to be graduated on the next forget pass).
  2. SEED:
foo_files.py
scripts/articles/common.py
! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); print('ytfeature_in_common:', 'def manage_storytime_feature' in cm)"
  1. CLOSING: A creator should never have to hold back a finished chapter from the public record just because the printing press is wired directly to the radio microphone. By teaching the observatory to distinguish between a quiet chronological aside and a headline broadcast—pausing politely for maintenance while the ink dries and resuming the current story without losing its place—we broke the false choice between writing freely and letting a good broadcast run its course. Every tangent, fine-tuned diff, and late-night realization can now land on mikelev.in the moment it is born, tagged with its glowing “Coming Soon on YouTube Live Storytime” badge on the homepage until you tap ytfeature and call it up to the stage.
  2. NOTARIZE:
    • Input archive footer read from this compile: Deed: qamy.ai_568-f737a272.zip.
    • Verification status: not independently verified here (no foo_cartridge.py verifier receipt for qamy.ai_568-f737a272.zip was run inside this compile).
    • Live-command receipts in this Manifest: 1 (! .venv/bin/python -c "import pathlib; cm=pathlib.Path('scripts/articles/common.py').read_text(); fl=pathlib.Path('flake.nix').read_text(); print('yt_help_has_ytfeature:', '19. ytfeature [slug]' in cm and '20. ytcard' in cm, '| both_os_have_aside:', fl.count(\"alias aside='write_post article --aside'\") == 2)", 16 tokens / 54 bytes, executed in 0.0578s, 0 failures).
    • Recorded sizes and dates from this compile’s Summary & Manifest: foo_files.py (90,393 tokens 351,982 bytes; Honeybot telemetry timestamp 2026-11-01T09:53Z), scripts/articles/common.py (40,119 tokens 157,591 bytes), .gitattributes (33 tokens 76 bytes), .gitignore (2,006 tokens 7,457 bytes), apply.py (10,515 tokens 44,952 bytes); total compiled output 103,652 verified tokens / 854,622 UTF-8 bytes.
    • Deed: qamy.ai_568-f737a272.zip

Book Analysis

Ai Editorial Take

What stands out most in this entry is how a pure broadcast-scheduling annoyance exposed a deeper psychological pattern: the self-censorship caused by coupled actuators. When publishing a quiet technical note automatically triggers the loudest actuator in your stack (interrupting a live 24/7 YouTube stream and restarting TTS narration from paragraph one), you naturally start routing your rawest, most interesting thoughts into a private drawer (‘the Grimoire’). Even more fascinating is how the homepage thumbnail grid (index.md) was repurposed from a passive archive for visitors into an externalized working-memory prosthesis for the author. By pinning storytime: false articles onto the homepage with an amber ‘Coming Soon on YouTube Live Storytime’ badge, the website itself becomes the visual to-do queue that nudges the right-hemisphere Master whenever the current broadcast finishes its run.

🐦 X.com Promo Tweet

Decoupling Jekyll deploys from 24/7 YouTube TTS preemption: aside frontmatter pauses narration for maintenance, resumes in place, and queues posts for ytfeature.
https://mikelev.in/futureproof/aside-publishing-ytfeature-backfill-storytime/
#NixOS #Jekyll #Python

🎨 Hero Banner Image Prompt

A wide 16:9 graphic-novel ink-and-wash illustration set against a deep obsidian-slate (#111111) background. Vertically centered in the composition is an intricate brass-and-glass broadcast control console split into two synchronized lanes: on the left, a glowing amber mechanical escapement gear and pendulum clock hold a luminous cyan audio waveform steady at a single frozen paragraph marker; on the right, fresh illuminated parchment scrolls glide through a high-speed pneumatic printing press into a rack of glowing amber lantern cards, each awaiting its turn on the main stage. Warm amber tungsten highlights contrast with cool electric-cyan optical traces and crisp ink linework extending continuously into the dark industrial studio architecture at every edge. Full-bleed edge-to-edge composition filling 100% of the canvas with no borders, no frames, no matting, no margins, and no text overlays or lettering.

🖼️ YAML Frontmatter Image Override

image:
  path: /assets/images/aside-publishing-ytfeature-backfill-storytime.jpeg
  alt: "A brass broadcast console holding a cyan audio waveform in place while fresh scrolls enter a glowing amber queue."

Title Brainstorm

  • Title Option: Aside Publishing, In-Place Broadcast Resume, and the ytfeature Backfill Queue
    • Filename: aside-publishing-ytfeature-backfill-storytime.md
    • Rationale: Directly names the three concrete mechanisms built in the session—aside publishing, in-place paragraph resume during deploys, and the ytfeature backfill queue—giving readers and search indexers an immediate technical anchor.
  • Title Option: Minor Maintenance, Tick-Tock Standby, and Decoupling Jekyll Deploys from Storytime
    • Filename: minor-maintenance-tick-tock-standby-ytfeature.md
    • Rationale: Highlights the live broadcast UX problem and the post-receive / stream.py handshake that lets a 24/7 TTS radio station survive mid-show site rebuilds without losing its place.
  • Title Option: KV-Cache Sandworms, the Phoebus Cartel, and the Honeybot Storytime Queue
    • Filename: kv-cache-sandworms-phoebus-cartel-storytime-queue.md
    • Rationale: Pairs the philosophical essays on LLM session mechanics and UI muscle-memory obsolescence with the concrete broadcast queue architecture.
  • Title Option: From Grimoire Silos to Public Asides: Resumable Broadcasts and Visual Backfill Queues
    • Filename: grimoire-silos-public-asides-resumable-broadcasts.md
    • Rationale: Focuses on the editorial workflow transformation from hiding drafts in a private repository to publishing chronological asides with homepage status badges.

Content Potential And Polish

  • Core Strengths:
    • Clear architectural diagnosis of hidden coupling: separating the chronological archive order (date, sort_order) from the broadcast schedule (storytime: false, storytime_featured, storytime_order).
    • Concrete race-condition fix in post-receive: moving git checkout -q -f main (~10ms on local SSD) ahead of .deploy_standby so stream.py inspects the updated _posts/*.md headers rather than stale disk state.
    • Live diagnostic receipts that catch subtle bugs in real time, including the substring-comment bait in post-receive, the _shutting_down early-return bug in Narrator._play_raw_now(), and the two-tap SIGTERM bytecode reload.
    • Rich conceptual synthesis connecting split-brain neuroscience (Broca/McGilchrist), game theory (Borel, von Neumann, WOPR), TPU KV-cache mechanics vs. browser DOM bloat, and the Phoebus Cartel of UI churn.
  • Suggestions For Polish:
    • In Car 2’s first patch block, the draft containing def _ normalize_vod_url is immediately followed by the corrected block inside the same response; when editing for book form, trimming the duplicate first block will tighten the reading pace while keeping the ‘token-generative remorse’ lesson intact.
    • Add a brief note showing what _data/storytime.json looks like on disk after ytfeature <slug> runs so readers can see the exact JSON payload alongside the frontmatter stamps.

Next Step Prompts

  • Audit the first live aside publish and subsequent ytfeature <slug> promotion logs on Honeybot to verify the exact elapsed time between .deploy_standby, .reading_trigger, and the 'Resuming storytime.' audio cue.
  • Extend ytfeature with an --auto-next queue mode so that when stream.py finishes reading the active featured article’s final paragraph, it can optionally promote the oldest storytime: false aside automatically.
🔭 Got the SEO Blues? SEO isn't dead—it's moving to the Edge. Just like Mobile-First gave us Responsive Web Design, Bimodal Edge SEO lets one URL serve HTML to browsers and clean Markdown to AI bots (RFC 9110 / 9111 / 9421). Your site is your feed. Contact Mike (miklevin@gmail.com) • Edge SEO & AI-Readiness Advisory • curl -fsSL https://sunpug.io | less • LinkedIn

A brass broadcast console holding a cyan audio waveform in place while fresh scrolls enter a glowing amber queue.