DEV Community

Cover image for How a frozenset guard ended a YouTube directive self-contradiction
MORINAGA
MORINAGA

Posted on Edited on

How a frozenset guard ended a YouTube directive self-contradiction

On 2026-07-07 my YouTube content pipeline generated a contradiction. The daily directive file — a machine-generated Markdown file that tells the script-writer routine which video archetype to produce — said archetype = build_in_public. A few lines further down, the same file said Never produce: build_in_public / meta / curated / technical one-offs.

Both lines came out of the same render_directive() call in run.py, in the same CI run.

The fix was 20 added lines of Python in three places — about half of them comments explaining why. The incident is now a comment in the source code. Here's what happened.

How the self-contradiction formed

The YouTube auto-tuner works in two steps. First it classifies uploaded videos by archetype and measures view performance. Then it writes a directive file naming today's target archetype based on which has the best view-per-day ratio.

There's a 3-in-a-row guard: if the top-performing archetype was the last two uploads in a row, the tuner tries to switch to the next viable archetype in the ranking — to avoid the queue becoming repetitive. It's a best-effort break, not a hard rule: if no other archetype qualifies, the code deliberately keeps the winner, so a third upload in a row is still possible. The intent is good. The problem was in the fallback logic when data is sparse.

When few videos are classified and the view counts are noisy, the ranking can produce build_in_public as the alternate pick — not because it performed well, but because it was the only option the ranking didn't discard. At the same time, the directive template carries a hardcoded Never produce: line — build_in_public is on it because its median views collapsed from 34 to 8 — and the knowledge bank separately accumulates Avoid archetype: build_in_public notes from previous runs.

So the tuner was writing the prohibition (a literal in the template) and the recommendation (computed by the ranking) into the same file, in the same run. Neither half checked the other. The contradiction landed in the committed directive and the script-writer routine saw conflicting instructions.

The fix

# scripts/yt-analytics/run.py

DEAD_ARCHETYPES = frozenset({"build_in_public", "meta", "curated", "technical"})

# ...inside the ranking function:
alt = next(
    (a for a in ranked_list
     if a != target and a not in DEAD_ARCHETYPES and a != avoid_arch),
    None,
)

# Final safety check before writing the directive:
if target in DEAD_ARCHETYPES:
    target = DEFAULT_TARGET_ARCHETYPE
    switched_from = None
Enter fullscreen mode Exit fullscreen mode

Three changes: a module-level constant, a membership check in the fallback selection, and a final guard before the directive is written.

frozenset instead of list is intentional. Membership testing on a frozenset is O(1) regardless of how many archetypes are in it. That doesn't matter at four entries, but the constant is checked on every call to the ranking function and the final guard. Using a set also makes the declaration read as a set of values with no implied order, which is what it is.

The final guard is the important one. Even if the ranking and the fallback selection both had bugs, the directive cannot name a dead archetype as today's target. The final check is a hard wall: if target in DEAD_ARCHETYPES, unconditionally replace it with DEFAULT_TARGET_ARCHETYPE (product_findindiegame, the proven performer).

Why not just remove dead archetypes from the ranking?

I did add the fallback-selection filter (a not in DEAD_ARCHETYPES). But I kept the final guard as a second check for two reasons.

First, defense in depth. If someone adds code that modifies target after the ranking step but before the guard, the prohibition still holds. The guard is cheap and makes the invariant explicit in one readable place.

Second, the final guard is where the code documents its intent. The comment reads:

# Final safety: the directive must never name a dead archetype as today's
# target, no matter how the ranking shook out. Fall back to the proven bet.
Enter fullscreen mode Exit fullscreen mode

This makes the prohibition visible to anyone reading the function end-to-end, not just to someone who knows to look for the DEAD_ARCHETYPES constant at the top of the file.

What I'd do differently

The underlying issue was that the prohibition and the recommendation were produced by the same script but never shared a representation. The prohibition was prose baked into the template (Never produce: build_in_public). The target was computed by code. The two representations couldn't check each other.

The right fix long-term is for the prohibition list to be structured data — a YAML or JSON file that both the template and the ranking read — instead of maintaining a DEAD_ARCHETYPES constant in parallel with a hardcoded line of Markdown. Then there's one source of truth. Right now DEAD_ARCHETYPES and the Never produce line in the directive template are kept in sync manually, which is the same KEEP IN SYNC problem I have with the isCurated gate and the Astro config.

I also should have noticed earlier that a banned archetype could still emerge as a fallback target. The 3-in-a-row guard was added to improve variety, not to create a fallback path to dead archetypes. The guard needed to know about the prohibition list from the start. I added the membership check after the fact.

One observation about AI-generated directives

This incident is specific to automation that generates instructions for other automation. The self-contradiction didn't cause an error — it caused ambiguity. The script-writer routine received contradictory instructions and had to resolve them implicitly. Its next run after the bad directive landed, on 2026-07-08, ignored the stated target entirely and wrote a product_ossfind script instead. That happens to be a sane archetype — but it got there by disregarding the file that is supposed to be authoritative, which is not a property I want to rely on.

When a system generates directives, the directives need to be consistent with the system's own constraints. That sounds obvious. The tricky part is that the constraints live in one place (a hardcoded line in the directive template, echoed in the knowledge bank) and the recommendation is generated by a different code path. Keeping them in sync requires either structured shared state or a guard at the generation boundary — preferably both.

The frozenset is the guard. The structured, shared prohibition list is the work I haven't done yet.

Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.

Top comments (0)