<?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: GGGODLIN</title>
    <description>The latest articles on DEV Community by GGGODLIN (@gggodlin).</description>
    <link>https://dev.to/gggodlin</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%2F4233114%2F73aaf2d1-8da1-4817-a39c-d15e6158bfdd.jpg</url>
      <title>DEV Community: GGGODLIN</title>
      <link>https://dev.to/gggodlin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gggodlin"/>
    <language>en</language>
    <item>
      <title>Resurrecting the 1856 Victorian Signal Box with Kiro Spec-Driven Development &amp; Property-Based Testing (Kiroween 2026)</title>
      <dc:creator>GGGODLIN</dc:creator>
      <pubDate>Sun, 08 Nov 2026 04:43:41 +0000</pubDate>
      <link>https://dev.to/gggodlin/resurrecting-the-1856-victorian-signal-box-with-kiro-spec-driven-development-property-based-oae</link>
      <guid>https://dev.to/gggodlin/resurrecting-the-1856-victorian-signal-box-with-kiro-spec-driven-development-property-based-oae</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This technical blog post is written as part of the **Kiroween 2026 Hackathon&lt;/em&gt;* (&lt;code&gt;Resurrection&lt;/code&gt; Category + &lt;code&gt;Best Startup Project&lt;/code&gt; + &lt;code&gt;Best Demo&lt;/code&gt;).*&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Control Tower Demo&lt;/strong&gt;: &lt;a href="https://blog.gggodlin.com/kiroween-signal-box/" rel="noopener noreferrer"&gt;https://blog.gggodlin.com/kiroween-signal-box/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/GGGODLIN/kiroween-signal-box" rel="noopener noreferrer"&gt;https://github.com/GGGODLIN/kiroween-signal-box&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Devpost Submission&lt;/strong&gt;: &lt;a href="https://devpost.com/software/kiroween-signal-box" rel="noopener noreferrer"&gt;https://devpost.com/software/kiroween-signal-box&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;45s Launch Film&lt;/strong&gt;: &lt;a href="https://youtu.be/qXKqfpr7NzE" rel="noopener noreferrer"&gt;https://youtu.be/qXKqfpr7NzE&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6aj2xnsn7tmbrgfno4sa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6aj2xnsn7tmbrgfno4sa.png" alt="Signal Box Control Tower" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Problem: Concurrent AI Coding Agents Colliding on Shared Tracks
&lt;/h2&gt;

&lt;p&gt;When engineering teams run multiple autonomous AI coding agents in parallel—a &lt;code&gt;Builder&lt;/code&gt; agent editing application code, a &lt;code&gt;Migrator&lt;/code&gt; agent altering database schemas, a &lt;code&gt;Deployer&lt;/code&gt; agent pushing releases, and a &lt;code&gt;Verifier&lt;/code&gt; agent running integration audits—agents routinely collide on shared resources. Even worse, traditional example-based unit tests only test a handful of happy paths and miss multi-step interleaving bugs where two agents acquire conflicting locks after 8 or 10 steps.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;1856&lt;/strong&gt;, Victorian railway engineer &lt;strong&gt;John Saxby&lt;/strong&gt; solved this exact mutual-exclusion problem for steam locomotives using the &lt;strong&gt;Mechanical Tappet Interlocking Frame&lt;/strong&gt;: a physical bed of perpendicular steel locking bars beneath brass levers controlling track points, facing point locks (&lt;code&gt;FPL&lt;/code&gt;), and semaphore signals. Before a signalman could clear a signal, the steel tappets physically blocked any conflicting lever pull.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Kiroween 2026&lt;/strong&gt;, we built &lt;strong&gt;Signal Box (&lt;code&gt;LeverFrame&lt;/code&gt;)&lt;/strong&gt; to resurrect Saxby &amp;amp; Farmer's 1856 Victorian mechanical interlocking frame as a deterministic, MCP-enabled mutual-exclusion control tower for parallel AI agents—specified and verified end-to-end with &lt;strong&gt;Kiro&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. How Kiro Transformed Our Development Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A. Spec-Driven Development (&lt;code&gt;/.kiro/specs/&lt;/code&gt;) vs. Vibe Coding
&lt;/h3&gt;

&lt;p&gt;If you try to "vibe code" an 8-lever railway interlocking frame with 6 track blocks, crossover points, facing point locks, and back-locks, an LLM will inevitably conflate the locking rules with the state transitions or forget symmetric reverse locks.&lt;/p&gt;

&lt;p&gt;Using &lt;strong&gt;Kiro's Spec-Driven Development&lt;/strong&gt; (&lt;code&gt;/.kiro/specs/lever-frame/requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, and &lt;code&gt;tasks.md&lt;/code&gt;), we first expressed all 8 mechanical interlocking invariants in formal &lt;strong&gt;EARS (&lt;code&gt;WHEN ... THE SYSTEM SHALL ...&lt;/code&gt;)&lt;/strong&gt; syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;EARS-ILK-01&lt;/code&gt;: &lt;em&gt;WHEN Lever #1 (North Up Home Signal) is pulled to REVERSE, THE SYSTEM SHALL require Lever #2 (Junction Crossover) at NORMAL and Lever #3 (Facing Point Lock) at REVERSE, and SHALL mechanically lock Levers #2, #3, #4, and #6.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EARS-ILK-04&lt;/code&gt;: &lt;em&gt;WHEN Lever #4 (South Branch Home Signal) is pulled to REVERSE, THE SYSTEM SHALL require Lever #2 at REVERSE and Lever #3 at REVERSE, preventing simultaneous occupation of &lt;code&gt;junction-throat&lt;/code&gt; and &lt;code&gt;schema-bridge&lt;/code&gt;.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having &lt;code&gt;requirements.md&lt;/code&gt; and &lt;code&gt;design.md&lt;/code&gt; pinned in &lt;code&gt;/.kiro/specs/&lt;/code&gt; meant Kiro generated the exact tappet locking matrix (&lt;code&gt;src/lib/interlocking.ts&lt;/code&gt;) with traceable EARS rule IDs on every single lock rejection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo69tm4dyipdwerxux7cw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo69tm4dyipdwerxux7cw.png" alt="Tappet Matrix and EARS Rules" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Steering Docs (&lt;code&gt;/.kiro/steering/&lt;/code&gt;): Enforcing SUT vs. Independent Oracle Separation
&lt;/h3&gt;

&lt;p&gt;A classic failure mode in AI-generated tests is tautological testing—where the test copies the implementation's own helper function to compute the expected result.&lt;/p&gt;

&lt;p&gt;We used &lt;strong&gt;Kiro Steering Docs&lt;/strong&gt; (&lt;code&gt;/.kiro/steering/product.md&lt;/code&gt;, &lt;code&gt;tech.md&lt;/code&gt;, &lt;code&gt;structure.md&lt;/code&gt;) to enforce a non-negotiable architectural boundary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;System Under Test (&lt;code&gt;getInterlockPreset&lt;/code&gt;)&lt;/strong&gt;: Evaluates the lever-to-lever tappet locking matrix (&lt;code&gt;STANDARD_SAFE&lt;/code&gt; vs. the fault-injected &lt;code&gt;CURSED_MISSING_CROSSOVER_LOCK&lt;/code&gt; preset).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent Physical Topology Oracle (&lt;code&gt;evaluatePhysicalTopology&lt;/code&gt;)&lt;/strong&gt;: Completely decoupled from &lt;code&gt;presetId&lt;/code&gt; and lever rules; it inspects only the physical track-block occupancy (&lt;code&gt;north-approach&lt;/code&gt;, &lt;code&gt;south-branch&lt;/code&gt;, &lt;code&gt;junction-throat&lt;/code&gt;, &lt;code&gt;schema-bridge&lt;/code&gt;, &lt;code&gt;prod-mainline&lt;/code&gt;, &lt;code&gt;audit-siding&lt;/code&gt;) and switch geometry after every step:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;P1_NO_CONFLICTING_ROUTES&lt;/code&gt;: No two active signals may ever occupy overlapping physical track blocks simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;P2_SIGNAL_POINT_LOCK_INTEGRITY&lt;/code&gt;: Every active signal must have its required points aligned and facing point locks plunged.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  C. Stepwise Property-Based Testing (PBT) Exorcist (&lt;code&gt;src/lib/pbt-exorcist.ts&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Kiro's emphasis on &lt;strong&gt;Property-Based Testing (PBT)&lt;/strong&gt; is where Signal Box shines. Instead of checking only final states or filtering out invalid inputs with &lt;code&gt;fc.pre()&lt;/code&gt;, our &lt;code&gt;runInterlockingExorcism(presetId)&lt;/code&gt; runner generates arbitrary sequences of lever pulls and releases via &lt;code&gt;fast-check&lt;/code&gt; and asserts &lt;code&gt;P1&lt;/code&gt; and &lt;code&gt;P2&lt;/code&gt; &lt;strong&gt;after every individual step&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;&lt;code&gt;STANDARD_SAFE&lt;/code&gt;&lt;/strong&gt;: 80 randomized multi-step runs (461 stepwise assertions) pass with &lt;code&gt;0&lt;/code&gt; violations and verified reachability witnesses (&lt;code&gt;clearedSignalCount: 19&lt;/code&gt;, &lt;code&gt;blockedInterlockCount: 100&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;&lt;code&gt;CURSED_MISSING_CROSSOVER_LOCK&lt;/code&gt;&lt;/strong&gt; (which simulates a subtle bug where &lt;code&gt;EARS-ILK-01&lt;/code&gt; forgets to lock out Signal #4 across the throat): &lt;code&gt;fast-check&lt;/code&gt; catches the physical train/agent collision on &lt;code&gt;["junction-throat", "schema-bridge"]&lt;/code&gt; inside an 11-step sequence and &lt;strong&gt;automatically shrinks it to a minimal 3-step counterexample (&lt;code&gt;3.67x&lt;/code&gt; reduction)&lt;/strong&gt;:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;{ leverId: 3, intent: "PULL" }&lt;/code&gt; — Engage Facing Point Lock #3&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ leverId: 1, intent: "PULL" }&lt;/code&gt; — Clear North Up Home Signal #1 (&lt;code&gt;Builder&lt;/code&gt; enters &lt;code&gt;junction-throat&lt;/code&gt; &amp;amp; &lt;code&gt;schema-bridge&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ leverId: 4, intent: "PULL" }&lt;/code&gt; — Clear South Branch Signal #4 (&lt;code&gt;Migrator&lt;/code&gt; collides on &lt;code&gt;junction-throat&lt;/code&gt; &amp;amp; &lt;code&gt;schema-bridge&lt;/code&gt; at &lt;code&gt;failingStepIndex: 2&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs6c2fy8jt3r987gqosv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs6c2fy8jt3r987gqosv.png" alt="PBT Exorcist Shrinking Counterexample" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  D. Kiro Agent Hooks (&lt;code&gt;/.kiro/hooks/&lt;/code&gt;) &amp;amp; MCP Server (&lt;code&gt;POST /api/mcp&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;We wired &lt;strong&gt;Kiro Agent Hooks&lt;/strong&gt; (&lt;code&gt;/.kiro/hooks/verify-interlocking-pbt.json&lt;/code&gt;) so that any edit to &lt;code&gt;src/lib/interlocking.ts&lt;/code&gt; or &lt;code&gt;/.kiro/specs/&lt;/code&gt; automatically triggers the &lt;code&gt;fast-check&lt;/code&gt; PBT Exorcist and blocks regressions before commit.&lt;/p&gt;

&lt;p&gt;Finally, we exposed the interlocking frame as a deterministic &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; tool surface (&lt;code&gt;request_route&lt;/code&gt;, &lt;code&gt;release_route&lt;/code&gt;, &lt;code&gt;inspect_interlock&lt;/code&gt;, &lt;code&gt;run_pbt_exorcism&lt;/code&gt; at &lt;code&gt;POST /api/mcp&lt;/code&gt;), allowing a crew of AI coding agents to request and release physical track clearances with zero race conditions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnsurkwp8t2f2n6318dur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnsurkwp8t2f2n6318dur.png" alt="MCP Dispatcher and Interactive Frame" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Try It Yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Web Control Tower&lt;/strong&gt;: &lt;a href="https://blog.gggodlin.com/kiroween-signal-box/" rel="noopener noreferrer"&gt;https://blog.gggodlin.com/kiroween-signal-box/&lt;/a&gt; — Pull brass levers, hear the WebAudio mechanical tappet latches, switch to the &lt;code&gt;CURSED_MISSING_CROSSOVER_LOCK&lt;/code&gt; preset, and step through the 3-step shrunk counterexample replay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Code &amp;amp; &lt;code&gt;/.kiro&lt;/code&gt; Specs&lt;/strong&gt;: &lt;a href="https://github.com/GGGODLIN/kiroween-signal-box" rel="noopener noreferrer"&gt;https://github.com/GGGODLIN/kiroween-signal-box&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>testing</category>
    </item>
  </channel>
</rss>
