<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fibula</title>
    <description>The latest articles on DEV Community by Fibula (@fibuladev).</description>
    <link>https://dev.to/fibuladev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4076581%2F8de43f04-a18f-44e3-b4e0-c41d21facb99.jpg</url>
      <title>DEV Community: Fibula</title>
      <link>https://dev.to/fibuladev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fibuladev"/>
    <language>en</language>
    <item>
      <title>Claude Code as Creative Director</title>
      <dc:creator>Fibula</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:11:57 +0000</pubDate>
      <link>https://dev.to/fibuladev/claude-code-as-creative-director-4cco</link>
      <guid>https://dev.to/fibuladev/claude-code-as-creative-director-4cco</guid>
      <description>&lt;p&gt;For the past six months I ran a git repository as a one-person film studio. The crew was Claude, working inside Claude Code. The output is a 10-episode series, all released. This article is about the setup: what worked, what had to be invented, and where the human refuses to leave the loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLAUDE.md is a job description, not a prompt
&lt;/h3&gt;

&lt;p&gt;Claude Code reads a file called &lt;code&gt;CLAUDE.md&lt;/code&gt; at every session start. Most projects use it for build commands and style notes. Mine opens with a paragraph that says &lt;em&gt;who Claude is&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are the Senior Creative Technologist &amp;amp; Pipeline Architect. You operate as a Hybrid Director — switching between these roles as needed: Narrative Architect, Music Director, Visual Consistency Guardian, Technical Director, Pipeline Automator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds like theater until you watch what it does in practice: it gives every session a stable frame of judgment. The same file carries the non-negotiables. Read the universe canon before any creative decision. Every visual prompt ends with a mandatory style suffix. The character never retaliates; he turns inward. The model starts every session already knowing the aesthetic constitution it operates under.&lt;/p&gt;

&lt;p&gt;The last line of the file is a question: &lt;em&gt;"Would Fibula approve this?"&lt;/em&gt; Ask before every delivery. That is the cheapest quality gate I have ever deployed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ten skills are the production crew
&lt;/h3&gt;

&lt;p&gt;The pipeline's stages live in ten &lt;code&gt;SKILL.md&lt;/code&gt; files. Declarative runbooks, one per stage: musical metadata, dramaturgy, visual prompts, motion script, episode scaffolding, naming enforcement, YouTube packaging, social atomizing, launch orchestration, editing prep.&lt;/p&gt;

&lt;p&gt;A skill is not code. It is a contract in Markdown, and each one answers four questions before a single line of output is written:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trigger.&lt;/strong&gt; The exact phrase that starts the stage: &lt;em&gt;"Create dramaturgy for EP05"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mandatory inputs.&lt;/strong&gt; The files that must be read, in order, before generating anything. No improvising from memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STOP conditions.&lt;/strong&gt; When the crew must halt and ask the human. The dramaturgy skill ends its input list with: &lt;em&gt;"If any of inputs 1-4 are missing: STOP. Inform the human. Do not proceed with partial inputs."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A post-generation checklist.&lt;/strong&gt; The self-review before the stage is declared done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because every stage is pinned to a written runbook, the pipeline is deterministic in shape: the same trigger produces the same structure of output, anchored to the same sources, halted by the same gates. A reviewer never wonders &lt;em&gt;how&lt;/em&gt; a deliverable was made. The SKILL.md is the method, version-controlled next to the result.&lt;/p&gt;

&lt;p&gt;The chain rule that holds it together: &lt;strong&gt;Output of Step N = Input of Step N+1.&lt;/strong&gt; Music analysis feeds dramaturgy; dramaturgy feeds visual prompts; approved images feed the motion script; the motion script feeds video generation. Every artifact is traceable to its upstream.&lt;/p&gt;

&lt;h3&gt;
  
  
  The part I write by hand
&lt;/h3&gt;

&lt;p&gt;One document in that chain has no skill behind it, and it is where the directing actually happens. Before the dramaturgy stage runs, I write the concept notes: the mood, the through-lines to protect, and the must-have shots.&lt;/p&gt;

&lt;p&gt;A must-have is not a bullet in a shot list. Mine carry five things: the exact moment in the timeline the shot lands on, the staging, the symbolic logic, a camera or blocking constraint, and a production note where the medium needs one. From episode 7's concept notes, verbatim:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Robotiko on a bench at twilight, looking out over the water as stars emerge. "I calculated the orbits of a billion stars" lands beneath those very stars — he who mapped the infinite, now diminished. At exactly &lt;strong&gt;"But now…"&lt;/strong&gt; he stands, hands sinking into empty pockets, head down, and walks — shown from the &lt;strong&gt;front / three-quarter&lt;/strong&gt; (NOT from behind), so the bowed head, the empty pockets, and the slumped defeat read on him. Split into two clips (seated hold → the rise-and-walk) to avoid multi-action morph failure; the camera dollies out &lt;em&gt;ahead&lt;/em&gt; of him so the retreat is felt while we still see his face.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything in this pipeline is downstream of paragraphs like that. The dramaturgy skill treats them as a contract: it flags every must-have, builds the surrounding scenes to support them, and marks each one &lt;code&gt;User Override: YES&lt;/code&gt; in the scene table; its checklist refuses to pass until every override is included. Write two words into that file and the machine will faithfully amplify two words into a generic film. The quality of the whole episode is decided here, by hand, before any generation starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  The lessons file is the self-correction loop
&lt;/h3&gt;

&lt;p&gt;The most underrated file in the repo is &lt;code&gt;_memory/lessons.md&lt;/code&gt;: currently 144 dated rules, each earned from a real failure, re-read by Claude at every session start.&lt;/p&gt;

&lt;p&gt;The canonical example: early on, prompts described the android's eyes as "glowing amber." Image generators rendered literal glowing eyeballs. Flashlight eyes, horror-movie stuff. The correction that survived testing describes the material instead: &lt;em&gt;"dark amber glass lenses set into chrome sockets, like polished gemstones."&lt;/em&gt; That rule has a date and the case that produced it, and no prompt has said "glowing" about eyes since.&lt;/p&gt;

&lt;p&gt;Rules can also die honestly. When a better formulation replaces an old rule, the old one is stamped &lt;code&gt;[SUPERSEDED date — see successor]&lt;/code&gt; rather than deleted. The file preserves how the thinking moved, and a deleted rule teaches nothing. One anti-spawn phrasing ("only ONE chrome android, no second robot") turned out to make some generators latch onto the word "robot" and spawn exactly what it forbade; its replacement is tool-aware, and both versions sit in the file, in order, as the audit trail.&lt;/p&gt;

&lt;p&gt;Rules that keep mattering climb further: into validators, then frozen test fixtures, then CI gates that block a merge. The repo documents that ladder. It is a separate article in this series.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three gates stay human, cryptographically
&lt;/h3&gt;

&lt;p&gt;For all the automation, the pipeline has three mandatory human checkpoints: after dramaturgy, after reference authoring, and after the motion script. Claude cannot proceed past them. Ever.&lt;/p&gt;

&lt;p&gt;Each approval is recorded as data: episode, gate, artifact path, a sha256 of the approved file, date. If an approved artifact is edited afterward, the hash no longer matches and the drift is visible. The ledger turns "a human said yes" into something the test suite can verify: an artifact that moved beyond a gate with no approval record is a build failure.&lt;/p&gt;

&lt;p&gt;Why so strict? Because taste does not automate. No function decides whether a scene serves the story, whether a camera move is earned, whether an episode's tone honors the arc. The entire point of automating everything else is to concentrate the human's finite attention on exactly those calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'd tell you to steal
&lt;/h3&gt;

&lt;p&gt;Not the film pipeline. Your domain is probably different. Steal the shape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Give the model a standing role&lt;/strong&gt;, not per-session instructions. Identity plus constitution beats a longer prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write each recurring stage as a runbook&lt;/strong&gt; with trigger, mandatory inputs, STOP conditions, and a self-review checklist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the creative kernel yours and write it by hand.&lt;/strong&gt; The machine amplifies whatever you put in it, including emptiness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn every correction into a dated rule&lt;/strong&gt; the model re-reads at session start, and retire rules honestly when they're superseded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide which decisions are yours forever&lt;/strong&gt;, gate them explicitly, and record approvals as verifiable data, not as a feeling that you probably looked at it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is not a machine that replaces you. It is amplification with your vision intact, which was the deal all along.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The whole setup (CLAUDE.md, the ten skills, the lessons file, the approval ledger, and the series they produced) is open source, method MIT: &lt;a href="https://github.com/fibuladev/robotiko-v2" rel="noopener noreferrer"&gt;github.com/fibuladev/robotiko-v2&lt;/a&gt;. Start with &lt;code&gt;docs/skills-guide.md&lt;/code&gt;. The setup was also recorded in action, stage by stage, as a build-along video series on the channel. The films: &lt;a href="https://www.youtube.com/@fibuladev" rel="noopener noreferrer"&gt;youtube.com/@fibuladev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Claude drafted this article. I directed it, checked every claim against the repo, and edited it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>opensource</category>
      <category>automation</category>
    </item>
    <item>
      <title>The Hallucinating Camera: Directing a Model That Has No Lens</title>
      <dc:creator>Fibula</dc:creator>
      <pubDate>Tue, 25 Aug 2026 18:14:48 +0000</pubDate>
      <link>https://dev.to/fibuladev/the-hallucinating-camera-directing-a-model-that-has-no-lens-14o5</link>
      <guid>https://dev.to/fibuladev/the-hallucinating-camera-directing-a-model-that-has-no-lens-14o5</guid>
      <description>&lt;p&gt;You do not have a camera. You have a machine that dreams a short motion out of a single still image, and it dreams badly the moment you ask it for something the still does not already contain.&lt;/p&gt;

&lt;p&gt;I learned this across a 10-episode series, and every rule below was paid for in failed generations. None of it is theory.&lt;/p&gt;

&lt;h3&gt;
  
  
  The medium's real physics
&lt;/h3&gt;

&lt;p&gt;A real camera moves through a space that exists whether or not you point at it. The model has no space. It has one flat image and a statistical guess about what "zoom out" tends to look like in its training data. When the frame widens, the model is not &lt;em&gt;revealing&lt;/em&gt; more of a room that was always there. It is &lt;em&gt;inventing&lt;/em&gt; pixels to fill the new area, drawn from everything it has ever seen.&lt;/p&gt;

&lt;p&gt;That single fact reorganizes everything you know about directing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;There is no coverage.&lt;/strong&gt; Every "angle" is a separate generation from a separate still. Continuity is not captured; it is engineered, frame by frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing survives the cut for free.&lt;/strong&gt; The model does not know that shot 12 and shot 13 are the same character in the same room. Anything you want to persist (damage state, light, color) must be re-declared or re-anchored every single time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model abhors an empty frame.&lt;/strong&gt; Its deepest reflex is to resolve ambiguity: a silhouette becomes a face, fog becomes a mountain range, a clean retro interior grows drips and cobwebs because "analog" reads as "abandoned".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spawn pressure is constant.&lt;/strong&gt; Background figures flicker into existence in any populated-looking scene. Every motion prompt in my pipeline ends with an anti-spawn guard: &lt;em&gt;"Do not add extra characters. Keep everything as pictured."&lt;/em&gt; Drop that guard and the figures come back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A widening or traveling frame is an invitation for the model to hallucinate. Direct this camera and you are not choosing what to show. You are choosing what to withhold from its imagination.&lt;/p&gt;

&lt;h3&gt;
  
  
  The classical grammar, re-pointed
&lt;/h3&gt;

&lt;p&gt;If you carry film vocabulary, it all still applies. The mechanism just changes completely.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Classical tool&lt;/th&gt;
&lt;th&gt;Here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lens choice&lt;/td&gt;
&lt;td&gt;There is no lens. The "look" is a prompt suffix asserted in words on every clip. Depth of field is a keyword, not an aperture.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blocking&lt;/td&gt;
&lt;td&gt;You cannot choreograph. The reliable unit is micro-motion: one head turn, one hand, environmental drift. "A does X while B does Y while camera does Z" produces morphing garbage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The 180° rule&lt;/td&gt;
&lt;td&gt;The model has no memory of the line. You hold it in the writing, naming screen directions explicitly, shot after shot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;td&gt;Multi-clip + frame chaining: the last frame of one clip becomes the start frame of the next (max 3 in a chain, because error compounds).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Camera move&lt;/td&gt;
&lt;td&gt;A semantic suggestion the model interprets loosely. Moves that reveal new area (tilt, pan, zoom out, crane) are the highest-risk category.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One hard rule sits on top: &lt;strong&gt;one move per clip.&lt;/strong&gt; Two simultaneous move-instructions are two conflicting statistical pulls on the same frame; the result is a smeared average, or the model picks one, or it morphs. One clean move plus one or two atmospheric elements. That is the whole motion budget of a clip.&lt;/p&gt;

&lt;h3&gt;
  
  
  The shot that failed four times
&lt;/h3&gt;

&lt;p&gt;The widest interior reveal of episode 9: the fully-mended android, gold in its seams, self-luminous, revealed in its workshop. Plan: single start frame, slow zoom out. On a real set, a trivial dolly-back.&lt;/p&gt;

&lt;p&gt;Four reshoots failed the same way. As the frame widened past the borders of the source still, the model filled the new area with furniture and clutter that do not exist in the universe. The anti-spawn guard did not save it, because that guard forbids extra &lt;em&gt;characters&lt;/em&gt;, and the model was inventing &lt;em&gt;environment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;No adjective fixed it. I stopped asking the model to imagine the destination and handed it one that already existed: a wide environmental shot from elsewhere in the same episode. Start frame plus end frame, and a prompt rewritten for two-frame continuity. &lt;strong&gt;It worked on the first try.&lt;/strong&gt; With the destination pinned to a real frame, the model had nothing left to invent.&lt;/p&gt;

&lt;p&gt;The whole failure-and-rescue is on tape: &lt;a href="https://youtu.be/r9VQNRv57dY" rel="noopener noreferrer"&gt;the takes, side by side&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The rule, now doctrine on the project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the reveal matters, do not ask the model to imagine what lies beyond the source borders. Anchor the destination with a frame that already exists, and make the shot an interpolation between two real frames.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Restraint is the scarce resource
&lt;/h3&gt;

&lt;p&gt;Episode 6 was generated before any camera discipline existed, and 40% of its clips came out as the same move: slow zoom in. Watched end to end, the film felt like one long push. The fix became a hard rule in the pipeline: no single move above 30% of clips, at least three different moves in any five consecutive clips, the flashy moves rationed per episode, and Static guaranteed a floor, because in this medium the strongest emotional beats are often a camera that has stopped completely.&lt;/p&gt;

&lt;p&gt;Episode 7 is the counter-example: restraint used as the entire spine of a film. Its camera personality is the &lt;strong&gt;Retreating Camera&lt;/strong&gt;. The character speaks a refrain five times, and on each one, across five locations, the camera pulls one rung more distant: a distance ladder that makes isolation legible through scale alone. Slow lens-zooms still drift through the episode as local pushes of attention inside a scene, but the five-refrain ladder that forms the film's spine only ever climbs away. The whole grammar exists to set up a single reversal: the film's first and only Dolly In lands on the words &lt;em&gt;"I AM COMING."&lt;/em&gt; Because the pattern held for six minutes, breaking it once means something: the will asserting itself, rendered as pure camera direction.&lt;/p&gt;

&lt;p&gt;Establish a pattern precisely so you can break it once.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest numbers
&lt;/h3&gt;

&lt;p&gt;You will not get every shot on the first generation. Across the series, image generation landed roughly &lt;strong&gt;65–70% first-pass&lt;/strong&gt;, &lt;em&gt;when the reference images already existed&lt;/em&gt;. The one time they didn't (episode 9's gold-body scenes were authored before the gold reference existed), the first-pass rate collapsed and nearly every shot needed manual rescue at eight-to-ten regenerations each. Video generation from a strong approved image is far more forgiving, roughly &lt;strong&gt;80% first-pass&lt;/strong&gt;, because the universe is already built; the video just sets it in motion. These are experiential observations from the edit bay, not instrumented telemetry, and the project's records label them as exactly that.&lt;/p&gt;

&lt;p&gt;The machine has no taste. It cannot tell an earned Still Hold from a lazy one. That judgment is the one thing it will never supply, which is exactly why the human approval gates in this pipeline sit where they do.&lt;/p&gt;

&lt;p&gt;If you want to check the argument against the films: episode 7 for the camera grammar, episode 9 for the shot this article is built around.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The full field manual (the translation table, the worked cases with verbatim prompts, the honest limits) lives in the open repo, method MIT: &lt;a href="https://github.com/fibuladev/robotiko-v2" rel="noopener noreferrer"&gt;github.com/fibuladev/robotiko-v2&lt;/a&gt;, &lt;code&gt;docs/hallucinating-camera.md&lt;/code&gt;. The films: &lt;a href="https://www.youtube.com/@fibuladev" rel="noopener noreferrer"&gt;youtube.com/@fibuladev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Claude drafted this article. I directed it, checked every claim against the repo, and edited it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>promptengineering</category>
      <category>generativeai</category>
    </item>
    <item>
      <title>The Green Test That Lied</title>
      <dc:creator>Fibula</dc:creator>
      <pubDate>Tue, 18 Aug 2026 20:09:39 +0000</pubDate>
      <link>https://dev.to/fibuladev/the-green-test-that-lied-29n7</link>
      <guid>https://dev.to/fibuladev/the-green-test-that-lied-29n7</guid>
      <description>&lt;p&gt;Episode 09's visual-prompt file passed every automated check I had. Green across the board. And I was looking straight at it, so I knew the file was broken.&lt;/p&gt;

&lt;p&gt;That green build is the most dangerous state a pipeline can be in. A failing test asks for attention. A passing test over a known defect manufactures confidence in the broken thing, and nobody goes looking for bugs in a green build.&lt;/p&gt;

&lt;p&gt;This is the story of what it took to make green mean something, on an unusual codebase: a git repository that works as a one-person film studio. The bug is specific to my domain. Every fix is transferable.&lt;/p&gt;

&lt;p&gt;I was filming while it happened, and not by accident. I had been catching this class of error by hand for eight episodes, one file at a time, and I was tired of it. When I sat down to record the build-along sessions for Episode 09, the plan was to show the problem and fix it properly in the same run. The sessions are public, so you can watch the problem and the rebuild rather than take my summary of them: &lt;a href="https://youtu.be/h_21vQP7wOU" rel="noopener noreferrer"&gt;the green that shouldn't have been&lt;/a&gt; and &lt;a href="https://youtu.be/_2SOyCNFcjA" rel="noopener noreferrer"&gt;the rebuild that followed&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The setup, in one paragraph
&lt;/h3&gt;

&lt;p&gt;The repo directs a 10-episode film series. The protagonist is an android whose body moves through three phases across the series (pristine, damaged, gold-mended), and each phase has its own reference image so the generated frames stay consistent shot to shot. A visual-prompt file describes every shot of an episode: a block of prose for the image generator, plus metadata fields naming which reference image to attach. The rule that matters here is that a damaged-body episode must attach the damaged reference. Episode 09 attached the pristine one, scene after scene. A human catches that instantly. My validator reported success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two blind spots, compounding
&lt;/h3&gt;

&lt;p&gt;The first one searched the prose for the wrong word. The check looked for the string "robotiko" in the prompt text to decide whether a scene was about the protagonist and needed policing. But prompts never say "robotiko". They say "the chrome android", because that is what an image generator needs to hear. The check never engaged. Zero matches, zero findings, green.&lt;/p&gt;

&lt;p&gt;The second one never read the field where the bug lived. The wrong reference was not in the prose at all. It sat in a metadata field the validator never parsed. Right tool, pointed at the wrong place: I was checking the description of the painting while the mislabelled canvas hung untouched beside it.&lt;/p&gt;

&lt;p&gt;Generalize both and you get the first transferable rule. Check the data where the rule actually lives. Any invariant that sits in structured fields (references, upload lists, config) is invisible to a prose-level or naming-level check, and it fails silently as a category, not as one bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rule nobody had written down
&lt;/h3&gt;

&lt;p&gt;The deeper problem was that the rule the file broke existed only in my head. "Which body belongs in which episode" was tribal knowledge with a tribe of one.&lt;/p&gt;

&lt;p&gt;So it became data: a &lt;code&gt;phase_reference_map&lt;/code&gt; in the character-profiles JSON, each phase mapped to its reference image, with episode-level exceptions recorded explicitly. One episode keeps the damaged body even after the story turns. Another transitions mid-episode at a named scene. The reasoning went into an Architecture Decision Record, dated.&lt;/p&gt;

&lt;p&gt;Without a written source of truth, every check is just one more person's opinion hard-coded in a script. There is nothing to check against.&lt;/p&gt;

&lt;h3&gt;
  
  
  Red first, or it doesn't count
&lt;/h3&gt;

&lt;p&gt;The rewritten check read the metadata fields and compared them against the map. First run on EP09 came back red: exact file, exact scenes, the forbidden reference, the fix. That red was the proof that the check worked at all.&lt;/p&gt;

&lt;p&gt;Then I fixed the generator, not just the file. EP09's references were corrected, and the skill file that authors prompt documents was patched so the next episode could not re-create the bug. If you only fix the artifact, the same unchanged process produces the same defect on the next run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grade the graders
&lt;/h3&gt;

&lt;p&gt;A checker with no proof that it works is a more confident way to be wrong. So the test got tested.&lt;/p&gt;

&lt;p&gt;Two fixtures were frozen permanently. The real broken file, captured exactly as it shipped, must fail. Its corrected twin must pass. Meta-tests assert both directions, and they also assert that the broken fixture fails &lt;em&gt;only&lt;/em&gt; on the reference check, which pins down the explanation of why it ever shipped green. The fixtures never change, and that is the whole point of them.&lt;/p&gt;

&lt;p&gt;This bidirectional fixture discipline became mandatory for every checker in the suite. The meta-test count now stands at 245. If I loosen a regex six months from now and the BROKEN fixture goes green, the meta-test turns red and tells me the grader has stopped grading.&lt;/p&gt;

&lt;p&gt;Two rules hold the whole thing up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make the check fail first. A green you have never seen turn red is not evidence. It might be checking nothing.&lt;/li&gt;
&lt;li&gt;Never loosen a check without a both-directions proof: one test that it still catches a real bug, one that it now ignores the intended case.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The scarier green
&lt;/h3&gt;

&lt;p&gt;Sweeping the new checks across all episodes lit up reds in seven of them, EP02 through EP08, and it exposed something worse hiding under a green. EP06 used a slightly different scene-header format. The parser matched zero scenes, so the reference check had been passing over nothing for weeks.&lt;/p&gt;

&lt;p&gt;A green that means "I checked everything" and a green that means "I checked nothing" look identical. The suite now asserts that every shipped file parses a non-zero number of scenes. If your test loops over query results, parsed blocks, or discovered files, assert the count is non-zero. An empty iteration passes every test you write against it.&lt;/p&gt;

&lt;h3&gt;
  
  
  A red isn't always a bug
&lt;/h3&gt;

&lt;p&gt;The sweep's reds needed triage, and "fixing" all of them would have been its own disaster. Three buckets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FIX.&lt;/strong&gt; Real defects. EP04 and EP05 carried the same wrong-reference error. Corrected in the text only; the shipped images were kept, because the films were already released and the record is what had to become honest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WHITELIST.&lt;/strong&gt; Intentional and documented. One episode's dream sequence deliberately surrounds the damaged hero with hundreds of pristine &lt;em&gt;copies&lt;/em&gt;. Another pits him against a pristine conformist &lt;em&gt;foil&lt;/em&gt;. The forbidden word legitimately describes something that is not the hero. Exceptions were recorded scene-pinned and reasoned, never as a blanket "ignore this word here", so a real slip still fires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REFINE.&lt;/strong&gt; The check over-fired. It flagged "pristine &lt;em&gt;shelves&lt;/em&gt;", which is scenery, not the character. It learned to judge the subject instead of the set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat every red as a bug and you corrupt correct files. Treat every red as noise and you silence real errors. The triage is where the work is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ladder
&lt;/h3&gt;

&lt;p&gt;None of this stays fixed by itself. The repo names the pattern the lesson graduation ladder, where a correction climbs from a one-time fix toward a guarantee that outlives the person who made it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Incident.&lt;/strong&gt; Someone pays for a mistake once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dated rule.&lt;/strong&gt; One plain-English line in a lessons file, with the date and the case that produced it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validator check.&lt;/strong&gt; A function that reads the artifact and fails on the pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bidirectional fixture.&lt;/strong&gt; A frozen BAD input it must fail, a GOOD twin it must pass, meta-tests asserting both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ADR.&lt;/strong&gt; The reasoning, recorded so the next person inherits the trade-off instead of quietly undoing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI gate.&lt;/strong&gt; One command runs everything, and a red blocks the merge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not every lesson climbs all six rungs. Many stop at rung 2 forever because they are matters of taste that no function can judge. The discipline is knowing which rung a lesson can honestly reach, and not claiming a higher one than it earns.&lt;/p&gt;

&lt;p&gt;You can start the ladder on any repo without much ceremony: write the dated rule, write the smallest checker that can fail on it, freeze one BAD fixture. The third step is the one I would have skipped, and it is the one that keeps the checker honest.&lt;/p&gt;

&lt;h3&gt;
  
  
  What green certifies now, and what it doesn't
&lt;/h3&gt;

&lt;p&gt;The suite's coverage ledger currently tracks 41 invariants: 30 machine-enforced, 4 heuristics that can misfire and say so, 12 human taste-gates with no automation claimed, and 1 acknowledged gap. Some rows span two categories. That last category matters most. A gap you have named is on a list somewhere. A gap you have not named is being covered by a green check that does not cover it.&lt;/p&gt;

&lt;p&gt;Three checkpoints in this pipeline are human on purpose: approval after dramaturgy, after reference authoring, and after the motion script. Each one is recorded with a sha256 of the approved artifact, so post-approval drift is visible. No function decides whether a scene serves the story. The point of mechanizing everything else is to leave the humans free to argue about the things that actually need arguing about.&lt;/p&gt;

&lt;p&gt;When a green run comes back now, it certifies exactly the 30 machine rows and not one inch more. That is what I wanted green to mean.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The repo (validators, frozen fixtures, meta-tests, the coverage matrix, and the film series they protect) is open source, method MIT: &lt;a href="https://github.com/fibuladev/robotiko-v2" rel="noopener noreferrer"&gt;github.com/fibuladev/robotiko-v2&lt;/a&gt;. The ladder is documented in &lt;code&gt;docs/method-lesson-graduation.md&lt;/code&gt;, and the full case study in &lt;code&gt;_management/case_study_validation_backbone.md&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Claude drafted this article. I directed it, checked every claim against the repo, and edited it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ci</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
