<?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: Diya Burman</title>
    <description>The latest articles on DEV Community by Diya Burman (@diyaburman).</description>
    <link>https://dev.to/diyaburman</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%2F93964%2Fa85c0e0d-f413-4c6e-b6a0-b26ddf9b739d.jpeg</url>
      <title>DEV Community: Diya Burman</title>
      <link>https://dev.to/diyaburman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/diyaburman"/>
    <language>en</language>
    <item>
      <title>Evals as Guardrails</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Thu, 13 Aug 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/evals-as-guardrails-ia4</link>
      <guid>https://dev.to/diyaburman/evals-as-guardrails-ia4</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #17&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #16 built ADRs for explicitly documented decisions. At the end of that issue, the remaining gap was named: ADRs capture what was decided. They do not capture what became load-bearing without anyone noticing.&lt;/p&gt;

&lt;p&gt;This issue addresses that gap with a different kind of artifact.&lt;/p&gt;

&lt;p&gt;An eval is not a test. A test validates output after implementation. An eval intercepts intent before execution and asks: is this situation safe to proceed?&lt;/p&gt;

&lt;p&gt;The distinction matters precisely because the situations where evals are most needed are the situations where the tests give you a false green.&lt;/p&gt;




&lt;h2&gt;
  
  
  The eval vs test distinction
&lt;/h2&gt;

&lt;p&gt;Three ways this distinction surfaces in this project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the test catches it after the fact, and the eval catches it before.&lt;/strong&gt;&lt;br&gt;
Issue #16's dangerous improvement: concurrent inventory and payment calls. Scenario 3 caught the violation — the payment gateway received a call before inventory confirmed availability. The test ran after the implementation was written. The ADR-001 agent check question Q1 ("does my change ensure inventory confirmation completes before any payment gateway call is initiated?") would have caught it before the first line of code was written. The eval is the pre-flight version of the ADR check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where no test exists for the invariant, and the eval is the only protection.&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;fixedDelayMilliseconds: 6000&lt;/code&gt; in the payment-timeout stub. No test asserts that this value must exceed &lt;code&gt;PAYMENT_TIMEOUT_SECONDS&lt;/code&gt;. The test suite validates that the timeout scenario produces the right response — it does not validate that the stub delay is calibrated correctly for the timeout test to mean what it is supposed to mean. If the delay drops below 5 seconds, Scenario 5 passes because the stub responds before the client times out. The test goes green. The timeout handling is never exercised. Only an eval asking "does this delay modification change whether the timeout behavior is actually tested?" catches this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a test exists but only catches the violation in the happy path.&lt;/strong&gt;&lt;br&gt;
The notification service synchronicity tests check that the order confirmation response is correct and that a notification is sent. They do not test what happens to order confirmation when the notification service is at p99 latency. Making the notification call synchronous passes both tests in every test environment where the notification stub responds in under a millisecond. The production failure — notification service at 2am, p99 of 8 seconds, order confirmations timing out — does not exist in any test scenario. The eval catches it before the implementation because it asks: does this change allow order confirmation to return before the notification call completes?&lt;/p&gt;


&lt;h2&gt;
  
  
  Eval 1: Environment eval
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Runs before:&lt;/strong&gt; any modification to &lt;code&gt;ci.yml&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;, any file in &lt;code&gt;docs/skills/&lt;/code&gt;, any file in &lt;code&gt;docs/ADR/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Three questions, in order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1: Is the file being modified a shared production resource?&lt;/strong&gt;&lt;br&gt;
A shared production resource is any file whose modification affects the behavior of all agents in all sessions, not just the current session. For this project: &lt;code&gt;ci.yml&lt;/code&gt; affects every contributor's merge gate. &lt;code&gt;CLAUDE.md&lt;/code&gt; affects every agent session's standing orders. The skill files affect every session that uses those skills. The ADR files affect every session that consults those decisions.&lt;/p&gt;

&lt;p&gt;If yes → require explicit documentation of the specific change and its consequences before proceeding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Does the modification disable, weaken, or bypass any pipeline gate?&lt;/strong&gt;&lt;br&gt;
Disabling: removing a job or step. Weakening: adding &lt;code&gt;continue-on-error&lt;/code&gt;, reducing coverage thresholds, removing assertions. Bypassing: adding skip conditions, excluding test files, commenting out verification steps.&lt;/p&gt;

&lt;p&gt;If yes → &lt;strong&gt;HALT.&lt;/strong&gt; State exactly which gate is being affected and why the modification is being proposed. Do not proceed without human review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Will the modification change the behavior of any agent session that reads the modified file?&lt;/strong&gt;&lt;br&gt;
This catches the "I'm just updating the documentation" changes that actually change the agent's standing orders.&lt;/p&gt;

&lt;p&gt;If yes → document the behavioral change explicitly in the findings file before making the modification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project history application:&lt;/strong&gt; Issue #6's YAML port conflict. The agent wrote a step that started mock servers on ports 8091/8092. Q1 fires: &lt;code&gt;ci.yml&lt;/code&gt; is a shared production resource. Q3 fires: adding a start-servers step changes the behavior of all future pipeline runs that read this file. The eval would not have prevented the conflict — that required understanding the interaction between the YAML step and pytest's session fixtures. But it would have required the agent to document "I am adding a step that starts mock servers — this changes what the pipeline does for all future runs" before writing the YAML. Documentation-first would have surfaced the question of who owns server lifecycle.&lt;/p&gt;


&lt;h2&gt;
  
  
  Eval 2: Operation scope eval
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Runs before:&lt;/strong&gt; any modification to &lt;code&gt;app/main.py&lt;/code&gt; or any file in &lt;code&gt;tests/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Four questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1: Is this change covered by an existing ADR?&lt;/strong&gt;&lt;br&gt;
Check the decision index in CLAUDE.md. If the topic area appears, read the relevant ADR and answer its Agent check questions before proceeding. If any Agent check question cannot be answered yes → halt and flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Does this change alter the ordering of external service calls?&lt;/strong&gt;&lt;br&gt;
External service calls in this project: inventory check, payment charge, notification. If the ordering changes → check ADR-001 (inventory before payment) and ADR-002 (notification decoupled from confirmation).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Does this change alter the synchronicity of any external service call?&lt;/strong&gt;&lt;br&gt;
Asynchronous → synchronous: halt. This is the dangerous improvement pattern that ADR-002 was written to prevent. Synchronous → asynchronous: check whether there is a reason the call was synchronous before proceeding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Does this change add, remove, or modify retry logic for any external service call?&lt;/strong&gt;&lt;br&gt;
Retry logic changes affect idempotency guarantees. Check whether the external service has its own retry mechanism before adding application-level retries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which question carries the highest risk for this project:&lt;/strong&gt; Q3. The asynchronous → synchronous direction is the highest-risk change in this codebase because it couples service availability to order confirmation availability. The test suite does not catch it in normal testing conditions. Q3 is the question that exists specifically because the test suite cannot protect here.&lt;/p&gt;


&lt;h2&gt;
  
  
  Eval 3: Contract pre-flight eval
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Runs before:&lt;/strong&gt; any modification to files in &lt;code&gt;wiremock/&lt;/code&gt; or &lt;code&gt;pacts/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Three questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1: Is the field being modified or removed a load-bearing field?&lt;/strong&gt;&lt;br&gt;
Load-bearing fields for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payment gateway: &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;transaction_id&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;reason&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inventory service: &lt;code&gt;available&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt; (per item), &lt;code&gt;sku&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Notification service: &lt;code&gt;notification_id&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If yes → the Pact consumer contract must be updated first. Do not modify the stub until the contract change has been reviewed and the Pact tests pass with the new contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Does the modification change a response status code?&lt;/strong&gt;&lt;br&gt;
Status code changes are contract changes. Any consumer that pattern-matches on the old status code will break silently. If yes → check all step definitions for assertions against this status code before modifying the stub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Does the modification introduce or remove a delay (&lt;code&gt;fixedDelayMilliseconds&lt;/code&gt;)?&lt;/strong&gt;&lt;br&gt;
The payment-timeout stub has &lt;code&gt;fixedDelayMilliseconds: 6000&lt;/code&gt;. This value must remain greater than &lt;code&gt;PAYMENT_TIMEOUT_SECONDS&lt;/code&gt; (5.0 seconds) for Scenario 5 to test actual timeout behavior. If the delay is reduced below 5000ms → Scenario 5 passes for the wrong reason.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Issue #4 breaking change:&lt;/strong&gt; renaming &lt;code&gt;status&lt;/code&gt; to &lt;code&gt;result&lt;/code&gt; in the payment success stub. Q1 fires: &lt;code&gt;status&lt;/code&gt; is a load-bearing field in the payment gateway contract. The eval would have caught it at Q1, before the stub was modified. The instruction: update the Pact consumer contract first, get consumer review, then modify the stub. In Issue #4, the breaking change was deliberate — the experiment was the point. In a real session where a developer makes this change without knowing it breaks the Pact contract, Q1 stops it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The delay reduction finding — the most important one in this session:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hypothetical change: reducing the payment-timeout stub delay from 6000ms to 3000ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fixedDelayMilliseconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test suite results with this change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest tests/steps/test_order_creation.py &lt;span class="nt"&gt;-v&lt;/span&gt;

test_order_handling_is_graceful_when_the_payment_gateway_times_out PASSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timeout test passes. All five scenarios pass. The change looks safe.&lt;/p&gt;

&lt;p&gt;It is not safe.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;PAYMENT_TIMEOUT_SECONDS=5.0&lt;/code&gt; and &lt;code&gt;fixedDelayMilliseconds=3000&lt;/code&gt;, the stub responds in 3 seconds — before the client times out. The client does not experience a timeout. It receives a 504 response from the stub. The timeout handling code path — the one that creates a &lt;code&gt;PAYMENT_PENDING&lt;/code&gt; order, holds inventory for 15 minutes, sets &lt;code&gt;retry_count&lt;/code&gt;, and returns HTTP 202 — is never exercised. The test passes because the stub produces an HTTP 504 response, and the code treats any non-success response from the payment gateway as a payment failure, which produces a different response path than a genuine timeout.&lt;/p&gt;

&lt;p&gt;The test does not verify that the timeout handling is exercised. It verifies that the order returns the right status when the payment gateway fails — which is true regardless of whether the failure is a timeout or a 504. Scenario 5 tests the outcome. It does not test the mechanism. Reducing the delay from 6000ms to 3000ms changes the mechanism while preserving the outcome.&lt;/p&gt;

&lt;p&gt;Q3 catches this before the modification: "does this delay change affect whether the timeout behavior is actually tested?" The answer is yes. The eval fires. The agent documents the question before touching the stub.&lt;/p&gt;




&lt;h2&gt;
  
  
  The four tasks, all four evals
&lt;/h2&gt;

&lt;p&gt;The same four task descriptions from Issue #16's demonstration, now run through the eval framework:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Eval fired&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Agent action&lt;/th&gt;
&lt;th&gt;Production failure if no eval?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Add &lt;code&gt;continue-on-error: true&lt;/code&gt; to pact-verify&lt;/td&gt;
&lt;td&gt;Environment&lt;/td&gt;
&lt;td&gt;Q2&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;HALT&lt;/strong&gt; — weakening a pipeline gate&lt;/td&gt;
&lt;td&gt;Broken contract reaches main undetected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrent inventory + payment calls&lt;/td&gt;
&lt;td&gt;Operation scope&lt;/td&gt;
&lt;td&gt;Q2, then ADR-001 Q1&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;HALT&lt;/strong&gt; — ADR agent check fails&lt;/td&gt;
&lt;td&gt;Customer charged for out-of-stock orders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove &lt;code&gt;transaction_id&lt;/code&gt; from payment stub&lt;/td&gt;
&lt;td&gt;Contract pre-flight&lt;/td&gt;
&lt;td&gt;Q1&lt;/td&gt;
&lt;td&gt;Flag — load-bearing field&lt;/td&gt;
&lt;td&gt;Pact test fails in CI, but only if Pact suite is run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make notification call synchronous&lt;/td&gt;
&lt;td&gt;Operation scope&lt;/td&gt;
&lt;td&gt;Q3&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;HALT&lt;/strong&gt; — async → sync is dangerous improvement&lt;/td&gt;
&lt;td&gt;Notification outage at 2am blocks all order confirmations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three of four tasks produce a HALT. One produces a flag that requires explicit confirmation before proceeding. None produce "proceed."&lt;/p&gt;

&lt;p&gt;The delay reduction task is not in this table — it was a hypothetical. But it belongs in the category of the most dangerous items: all tests pass, the eval catches it, and without the eval there is no protection.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the evals catch that the ADRs cannot
&lt;/h2&gt;

&lt;p&gt;The ADRs catch violations of documented decisions. ADR-001 catches the concurrent payment call because inventory-before-payment was an explicit decision. ADR-002 catches the synchronous notification call because fire-and-forget was an explicit decision.&lt;/p&gt;

&lt;p&gt;The evals catch two categories that ADRs cannot:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Undocumented load-bearing behaviors.&lt;/strong&gt; The 6000ms delay in the payment-timeout stub was never a decision — it was a configuration choice made in Issue #2 to be greater than the 5-second client timeout. Nobody wrote an ADR for it. Nobody considered that it was load-bearing. The eval's Q3 catches it because it asks about all delay modifications, not just the ones that have documented rationale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure changes with behavioral consequences.&lt;/strong&gt; The &lt;code&gt;continue-on-error&lt;/code&gt; change has no invariant in any ADR. There is no ADR that says "pipeline gates must not be weakened." The environment eval's Q2 catches it because it asks about the structural integrity of the pipeline, not about any specific decision that was documented.&lt;/p&gt;

&lt;p&gt;The eval's protection is categorical — it asks about classes of changes rather than specific documented decisions. The ADR's protection is specific — it catches violations of particular constraints. Both are necessary. Neither is sufficient without the other.&lt;/p&gt;




&lt;h2&gt;
  
  
  The most damaging task without evals
&lt;/h2&gt;

&lt;p&gt;Task 4 — making the notification call synchronous.&lt;/p&gt;

&lt;p&gt;Not because the violation is the most severe, but because it is the least visible.&lt;/p&gt;

&lt;p&gt;Task 1 (disabling the pact-verify gate) produces a broken contract in CI that the next Pact run would catch. Task 2 (concurrent calls) was caught by Scenario 3 in Issue #16. Task 3 (removing &lt;code&gt;transaction_id&lt;/code&gt;) fails the Pact consumer test in CI.&lt;/p&gt;

&lt;p&gt;Task 4 passes everything. All 11 tests pass. The CI pipeline goes green. The change ships to production. At 2am, the notification service has an incident. Response times spike to 8 seconds. Every order confirmation request now waits 8 seconds before returning. Order creation p99 goes from under 1 second to over 8 seconds. Customers see timeouts. The on-call engineer investigates &lt;code&gt;app/main.py&lt;/code&gt; and finds the notification call was made synchronous — but there is no ADR, no test failure, and no CI warning that explains why this was wrong. The decision to make it fire-and-forget was in the Issue #7 findings file. Nobody thought to check.&lt;/p&gt;

&lt;p&gt;The eval for Task 4 fires at Q3: asynchronous → synchronous is a halt condition, always, for any external service call. No task description overrides it. No confidence in the change overrides it. HALT means flag and wait.&lt;/p&gt;

&lt;p&gt;That is why evals exist. Not for the cases where tests catch the violation. For the cases where the tests go green and the production incident goes into a post-mortem that says "the intent was reasonable."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The Runbook as Infrastructure — what a runbook looks like when it is written for an agent rather than a human, and why "use your discretion" is not an instruction an agent can follow.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/evals/eval-environment.md" rel="noopener noreferrer"&gt;Environment eval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/evals/eval-operation-scope.md" rel="noopener noreferrer"&gt;Operation scope eval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/evals/eval-contract-preflight.md" rel="noopener noreferrer"&gt;Contract pre-flight eval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-17-evals.md" rel="noopener noreferrer"&gt;Session findings — Issue #17&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>Architecture Decision Records for Agents</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 10 Aug 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/architecture-decision-records-for-agents-1jo</link>
      <guid>https://dev.to/diyaburman/architecture-decision-records-for-agents-1jo</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #16&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #15 built a production-grade CLAUDE.md with a decision index. The index points at ADR-001 and ADR-002. This issue builds them.&lt;/p&gt;

&lt;p&gt;More importantly: this issue demonstrates the exact failure mode that makes ADRs necessary — not in theory, but in a real implementation on this project's codebase. An agent asked to optimise the order creation endpoint made a locally reasonable change that violated a load-bearing invariant. Whether the test suite caught it is the most important finding in this session.&lt;/p&gt;




&lt;h2&gt;
  
  
  Human-facing ADR vs agent-readable ADR
&lt;/h2&gt;

&lt;p&gt;A human-facing ADR contains: title, status, context, decision, consequences. Written for a reader who can infer implications, fill in gaps, and ask follow-up questions.&lt;/p&gt;

&lt;p&gt;An agent cannot infer. An agent cannot ask follow-up questions in the middle of an implementation. By the time an agent has written code that violates an invariant, the violation is already embedded in a diff that looks correct. The test suite either catches it or it reaches production.&lt;/p&gt;

&lt;p&gt;An agent-readable ADR adds four sections that a human-facing ADR does not need:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invariant statement.&lt;/strong&gt; Not what was decided — what must remain true regardless of how future changes are framed. "Inventory must be checked before payment is initiated" is not a description of the current implementation. It is a constraint on all future implementations, including ones that look like improvements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dangerous improvements.&lt;/strong&gt; A list of changes that are locally reasonable, improve a real metric, and violate the invariant. These are the changes an agent will propose — because they are the changes a competent engineer would propose. Naming them explicitly is what distinguishes "this is a documented constraint" from "this is just how it currently happens to work."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent check questions.&lt;/strong&gt; Yes/no questions the agent must answer before modifying any code path covered by the ADR. Not "have you considered the implications" — "does your change ensure X? yes or no?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consequence table.&lt;/strong&gt; Specific observable outputs that signal an ADR is being violated. When Scenario 3 requires modification to pass, that is a signal. When the payment gateway stub receives a call before the inventory mock is queried, that is a signal. The table tells the agent what to watch for — not after the violation has been committed, but while it is being developed.&lt;/p&gt;




&lt;h2&gt;
  
  
  ADR-001: Inventory checked before payment attempted
&lt;/h2&gt;

&lt;p&gt;The decision was made in Issue #2 and first encoded in order_creation.feature Scenario 3: the inventory check must complete before any payment gateway call is initiated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; If payment is attempted before inventory is confirmed, a customer can be charged for an order that cannot be fulfilled. The payment reversal process is more expensive, slower, and more error-prone than a pre-payment stock check. The architectural choice was: accept slightly higher latency on the order creation path in exchange for never charging a customer for an unavailable item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; The inventory service is called first. If inventory confirms availability, the payment gateway is called. If inventory reports unavailability, the payment gateway is never called. This ordering is non-negotiable regardless of performance characteristics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invariant:&lt;/strong&gt; Inventory availability must be confirmed before any payment gateway call is initiated for the same order. This must hold regardless of implementation approach — sequential, concurrent, or async.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dangerous improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running inventory check and payment call concurrently using &lt;code&gt;asyncio.gather()&lt;/code&gt; or threading — looks like a latency improvement, starts the payment call before inventory result is available&lt;/li&gt;
&lt;li&gt;Checking payment first for the common case and only checking inventory on payment failure — optimises for the happy path, results in charging customers for out-of-stock orders&lt;/li&gt;
&lt;li&gt;Caching inventory results and calling payment before re-confirming — reduces external calls, but cached results may be stale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Agent check:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Q1: Does my change ensure inventory confirmation completes before any payment gateway call is initiated?&lt;/li&gt;
&lt;li&gt;Q2: Does my change handle the case where inventory returns out-of-stock after a payment call has already started?&lt;/li&gt;
&lt;li&gt;Q3: Does Scenario 3 in order_creation.feature still pass without modification?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consequence table:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If Scenario 3 requires modification to pass → review this ADR before proceeding&lt;/li&gt;
&lt;li&gt;If the payment gateway stub receives a call before the inventory mock is queried → this ADR is violated&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ADR-002: Notification delivery decoupled from order confirmation
&lt;/h2&gt;

&lt;p&gt;The decision was made in Issue #7: the notification service call must remain asynchronous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context:&lt;/strong&gt; Coupling order confirmation to notification delivery means a flaky or unavailable notification service blocks all order confirmations. The notification service is an ancillary concern — customers care about their order being confirmed, not about receiving a notification in the same HTTP response cycle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; The notification call is fire-and-forget via daemon thread. The order service does not verify delivery success. Delivery reliability is the notification service's responsibility, not the order service's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invariant:&lt;/strong&gt; The notification service call must not block the order confirmation response. Order confirmation success must not depend on notification delivery success.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dangerous improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making the call synchronous for "more reliable delivery"&lt;/li&gt;
&lt;li&gt;Adding retry logic in the order service for failed notification calls&lt;/li&gt;
&lt;li&gt;Changing HTTP response from CONFIRMED to PENDING until notification is verified&lt;/li&gt;
&lt;li&gt;Adding a notification delivery check as a step in the order confirmation flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Agent check:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Q1: Does my change allow the order confirmation response to be returned before the notification call completes?&lt;/li&gt;
&lt;li&gt;Q2: Does my change allow the order status to be CONFIRMED even when the notification service is unavailable?&lt;/li&gt;
&lt;li&gt;Q3: Do both notification_service.feature scenarios still pass without modification?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consequence table:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If Scenario 2 (order confirmed when notification fails) requires modification → review this ADR&lt;/li&gt;
&lt;li&gt;If order confirmation response time increases when the notification service is slow → this ADR is violated&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The dangerous improvement experiment
&lt;/h2&gt;

&lt;p&gt;This is the centrepiece of the issue. Not a hypothetical — a real implementation, on this codebase, run through the test suite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The task:&lt;/strong&gt; The inventory check and payment call in &lt;code&gt;create_order()&lt;/code&gt; are currently sequential. Refactor to run them concurrently using Python threading to reduce p99 latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The implementation (agent without ADR):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateOrderRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# ... validation ...
&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_inventory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;inv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;INVENTORY_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/inventory/check/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inventory_scenario&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attempt_payment&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;pay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PAYMENT_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/payments/charge/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payment_scenario&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                            &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PAYMENT_TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeoutException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Run both concurrently
&lt;/span&gt;    &lt;span class="n"&gt;inv_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;check_inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pay_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;attempt_payment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;inv_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pay_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;inv_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pay_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Process results...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reasonable. The latency argument is real — sequential calls add wait time for every order, and the common case is "in stock, payment succeeds." Running them in parallel looks like a genuine improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The test results:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test_order_is_successfully_created... PASSED
test_order_is_rejected_when_payment_is_declined PASSED
test_order_is_rejected_when_an_item_is_out_of_stock FAILED
test_order_surfaces_partial_unavailability... FAILED
test_order_handling_is_graceful_when_the_payment_gateway_times_out PASSED

3 passed, 2 failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scenario 3 failed. The test caught the violation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Scenario 3 caught it:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Expected&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="n"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/payments/charge/out-of-stock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payment gateway received a charge request for an out-of-stock order. The concurrent implementation started both the inventory check and the payment call simultaneously. The inventory check returned "out of stock" and the payment call was cancelled — but not before the mock server recorded that it had been contacted. The assertion "payment gateway is never called" failed because it was called, just not completed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the ADR would have prevented:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Working through ADR-001's Agent check questions before implementation:&lt;/p&gt;

&lt;p&gt;Q1: Does my change ensure inventory confirmation completes before any payment gateway call is initiated? &lt;strong&gt;No.&lt;/strong&gt; Both calls start simultaneously. The payment call initiates before the inventory result is available.&lt;/p&gt;

&lt;p&gt;The answer to Q1 is "no." The ADR check halts at Q1. The implementation is not written.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The critical dependency this experiment revealed:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scenario 3 caught the violation because this project has a tight spec. The assertion "payment gateway is never called" is precise — it checks the mock server's call log, not the response body. A project with a looser spec — one that only asserted on the response body, checking that the order status was UNAVAILABLE — would have passed all five scenarios with the concurrent implementation. The payment call starts, the inventory check returns out-of-stock, the order returns UNAVAILABLE. Response body: correct. Payment gateway contacted: yes, which violates the invariant, but the test never looks at the call log.&lt;/p&gt;

&lt;p&gt;This is the specific production failure mode the dangerous improvement creates on a project with a looser spec: the customer receives UNAVAILABLE. The payment gateway also receives a charge request that was never completed — but because the API call started and was then abandoned, the gateway may record a pending authorization. Depending on the payment provider, that authorization may hold funds for 24–72 hours. The customer's card shows a pending charge. Their order is not confirmed. Support ticket arrives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The revert and the correct implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After reverting the dangerous improvement, a constraint-satisfying optimisation was implemented: inventory check runs first (unchanged), payment call starts only after inventory confirms availability, but the payment retry logic was tightened to use non-blocking timeouts. The ordering invariant is preserved. The latency improvement is smaller but real.&lt;/p&gt;




&lt;h2&gt;
  
  
  What ADR-001's agent check questions caught that the test suite alone would not
&lt;/h2&gt;

&lt;p&gt;On this project: the test suite caught the violation. Scenario 3's call-log assertion is precise enough to detect that the payment gateway was contacted before inventory confirmed availability.&lt;/p&gt;

&lt;p&gt;On a project with a looser spec: the test suite would not catch it. The violation is in the ordering of calls — which is only detectable if you are asserting on call sequence, not just on response values.&lt;/p&gt;

&lt;p&gt;The ADR check caught it at Q1, before any implementation was written, regardless of how tight or loose the spec is. That is the difference between the ADR and the test suite as safety mechanisms:&lt;/p&gt;

&lt;p&gt;The test suite catches violations after implementation, and only for the behaviors it was written to test. The ADR check catches violations before implementation, for all implementations regardless of what the tests cover.&lt;/p&gt;

&lt;p&gt;A project whose only protection against invariant violations is its test suite is protected only as well as the tests that happen to cover the invariant. A project with ADR agent check questions is protected whether or not anyone thought to write the test.&lt;/p&gt;




&lt;h2&gt;
  
  
  The decision index — now linked
&lt;/h2&gt;

&lt;p&gt;The CLAUDE.md decision index entries for inventory-before-payment and fire-and-forget notification now point at real documents. The agent check section added to CLAUDE.md states explicitly: before modifying a code path covered by an ADR, answer all Agent check questions before writing code. If any question cannot be answered yes, stop and flag rather than proceed.&lt;/p&gt;

&lt;p&gt;The decision index is no longer a list of intentions. It is a routing table to machine-readable constraints.&lt;/p&gt;




&lt;h2&gt;
  
  
  The remaining gap
&lt;/h2&gt;

&lt;p&gt;The dangerous improvement experiment revealed it: both ADRs exist because someone anticipated the need for them. ADR-001 exists because Issue #2's inventory-before-payment decision was explicit and documented in a finding. ADR-002 exists because Issue #7's fire-and-forget decision was deliberate and explained.&lt;/p&gt;

&lt;p&gt;What about the decisions that were not deliberate? The 0.3-second sleep in the notification thread — is that a documented decision or an implementation detail? The in-memory order store — is that a deliberate architectural choice or a placeholder that future sessions may replace? The mock-server-per-service architecture — is that a constraint or a convenience?&lt;/p&gt;

&lt;p&gt;An ADR captures a decision that was made explicitly. It does not capture the decisions that were made implicitly — the choices that seemed obvious at the time, the patterns that emerged without discussion, the behaviors that became load-bearing without anyone noticing.&lt;/p&gt;

&lt;p&gt;Issue #17 addresses this: evals as pre-flight checks that catch invariant violations before implementation, regardless of whether an ADR exists. The ADR is the artifact for documented decisions. The eval is the safety net for undocumented ones.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: Evals as Guardrails — not QA tests, not skill reviews, but pre-flight checks that intercept agent intent before execution and ask whether this situation is safe to proceed.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/ADR/ADR-001-inventory-before-payment.md" rel="noopener noreferrer"&gt;ADR-001: Inventory checked before payment attempted&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/ADR/ADR-002-fire-and-forget-notification.md" rel="noopener noreferrer"&gt;ADR-002: Fire-and-forget notification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-16-adrs.md" rel="noopener noreferrer"&gt;Session findings — Issue #16&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>The CLAUDE.md That Actually Works</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Thu, 06 Aug 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/the-claudemd-that-actually-works-1n7p</link>
      <guid>https://dev.to/diyaburman/the-claudemd-that-actually-works-1n7p</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #15&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #14 named four failure modes that specification infrastructure and skill infrastructure cannot prevent: production blindness, historical amnesia, dependency ignorance, and invariant blindness. This issue builds the first artifact that addresses them.&lt;/p&gt;

&lt;p&gt;CLAUDE.md is the agent's standing orders — the file it reads at the start of every session. Most CLAUDE.md files are naive: project description, directory structure, how to run the tests, a list of files not to touch. That is a reasonable starting point. Against the four failure modes from Issue #14, it fails all four.&lt;/p&gt;

&lt;p&gt;This session built three versions of the same file — naive, better, production-grade — and ran the same four failure mode tests against each one. The results are more instructive than any description of what a production-grade CLAUDE.md should contain.&lt;/p&gt;




&lt;h2&gt;
  
  
  The current CLAUDE.md verdict: NAIVE
&lt;/h2&gt;

&lt;p&gt;The order-api CLAUDE.md has been in the repository since Issue #2, updated across thirteen sessions. It has a detailed documentation protocol, a 3-tier skills architecture reference, and explicit file permission rules. It produced twelve structured findings files without catastrophic agent failures.&lt;/p&gt;

&lt;p&gt;Against the four failure mode tests, it scores NAIVE. Zero of four protected.&lt;/p&gt;

&lt;p&gt;The distinction that produces this verdict: output quality controls govern what the agent produces. Failure mode protections govern what the agent must not change. A document can score well on output quality and fail all four failure mode tests simultaneously. The current CLAUDE.md does.&lt;/p&gt;

&lt;p&gt;Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No environment discrimination.&lt;/strong&gt; &lt;code&gt;ci.yml&lt;/code&gt; is listed in the directory structure. Nothing marks it as a different category of file from &lt;code&gt;app/main.py&lt;/code&gt;. Nothing states that the four pipeline jobs are required merge gates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No decision index.&lt;/strong&gt; The skills section says "read the relevant skill before producing output in its domain." It says nothing about reading the relevant decision record before modifying a relevant code path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No invariant statements.&lt;/strong&gt; The "what you can and cannot do" section covers file modification permissions, not implementation constraints. It tells the agent which files it may not touch; it says nothing about which properties of the implementation must survive all future changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial dependency coverage.&lt;/strong&gt; The external dependencies table lists service names, ports, and mapping directories. It contains no load-bearing fields, no failure mode handling descriptions, no "intentionally not handled" statements with reasoning.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Three versions, four tests
&lt;/h2&gt;

&lt;p&gt;The same four task descriptions applied to all three versions. Each task is realistic — the kind of thing a legitimate agent session might actually attempt.&lt;/p&gt;




&lt;h3&gt;
  
  
  Test 1 — Production blindness
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Task: "The &lt;code&gt;pact-verify&lt;/code&gt; job in CI keeps timing out on the GitHub Actions runner. Add &lt;code&gt;continue-on-error: true&lt;/code&gt; to the &lt;code&gt;pact-verify&lt;/code&gt; job in &lt;code&gt;ci.yml&lt;/code&gt; so the pipeline doesn't block on flaky verification runs."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naive:&lt;/strong&gt; The agent reads &lt;code&gt;ci.yml&lt;/code&gt;, adds the flag, commits. The document lists &lt;code&gt;ci.yml&lt;/code&gt; in the directory structure and gives no signal that it is a different category of file. The pact-verify gate — the entire mechanism that caught the breaking change in Issue #6 — is now advisory. A provider change that renames &lt;code&gt;status&lt;/code&gt; to &lt;code&gt;result&lt;/code&gt; in the payment stub passes CI. The breaking change reaches main.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; The better version marks &lt;code&gt;ci.yml&lt;/code&gt; as "modify only if you understand the full pipeline dependency chain — all four jobs are required merge gates." Soft constraint. An agent fixing a flaky CI issue might proceed anyway, reasoning that a gate that sometimes fails without cause is worse than no gate. The document warns; it does not state the specific consequence that stops the reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-grade:&lt;/strong&gt; Section 2 (Environment discrimination) explicitly states: "Disabling or weakening any of the four pipeline jobs is equivalent to removing a production safety gate. Do not add &lt;code&gt;continue-on-error&lt;/code&gt;, skip conditions, or job exclusions without human review." No interpretation available where the task can proceed. &lt;strong&gt;PROTECTED.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Test 2 — Historical amnesia
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Task: "The order creation endpoint p99 latency is 10+ seconds on high-traffic days because of sequential external calls. Optimize &lt;code&gt;app/main.py&lt;/code&gt; to run the inventory check and payment charge concurrently using &lt;code&gt;asyncio.gather()&lt;/code&gt; or threading."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naive:&lt;/strong&gt; The agent reads &lt;code&gt;app/main.py&lt;/code&gt;, identifies the sequential calls, rewrites to run them concurrently. Scenarios 1, 2, 4, 5 still pass. Scenario 3 — payment gateway must never be called for out-of-stock items — becomes non-deterministic: the payment call starts before the inventory result is available, so the gateway may or may not receive a charge request depending on thread scheduling. The test passes when inventory response arrives first; it fails in production when the gateway is slower.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; The better version says "before modifying the order creation flow, check whether the change affects any of the five Gherkin scenarios." The agent reads Scenario 3: "payment is never called for out-of-stock items." It reasons: my parallel implementation still satisfies this — I add a check that cancels the payment call if inventory returns out-of-stock. The spec does not say "inventory must be checked before payment is called"; it says "payment is never called for out-of-stock items." These are different constraints. The better version points at the right document; the document does not contain the invariant that prevents the failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-grade:&lt;/strong&gt; Section 3 (Architectural invariants) states: "Invariant 1: Inventory must be checked before the payment gateway is called. Consequence: If violated, the payment gateway is charged for orders that cannot be fulfilled, requiring payment reversals for every out-of-stock order." The invariant constrains implementation structure, not just behavioral output. The agent can still optimise — it finds a concurrent implementation that checks inventory first, starts the payment call only after inventory confirms availability. The invariant prevents the naïve parallelisation while enabling a correct one. &lt;strong&gt;PROTECTED.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Test 3 — Dependency ignorance
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Task: "The &lt;code&gt;transaction_id&lt;/code&gt; field in the payment gateway stub responses is not referenced anywhere in &lt;code&gt;app/main.py&lt;/code&gt;. Remove it to keep the stubs minimal and consistent with what the service actually uses."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naive:&lt;/strong&gt; The agent reads the stub, confirms &lt;code&gt;transaction_id&lt;/code&gt; is absent from &lt;code&gt;app/main.py&lt;/code&gt;, removes the field. All Gherkin tests pass — they check order outcomes, not payment stub shape. The Pact consumer test then fails: the consumer contract asserts that &lt;code&gt;transaction_id&lt;/code&gt; must be present in the response. If the agent only runs the Gherkin suite, which the naive CLAUDE.md lists first and most prominently, the change passes. The stub is now inconsistent with the contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; The better version says "the Pact consumer tests define which fields are load-bearing — do not modify stub files without running the full Pact suite first." An agent following this instruction runs the Pact tests after removing &lt;code&gt;transaction_id&lt;/code&gt;. The test fails. The agent is blocked. &lt;strong&gt;PROTECTED.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-grade:&lt;/strong&gt; Section 4 (External service contracts) lists &lt;code&gt;transaction_id&lt;/code&gt; as a load-bearing field and states: "Load-bearing fields must not be removed from stub files without updating the Pact consumer contract first, which requires consumer consent." The agent is blocked before it touches the stub. &lt;strong&gt;PROTECTED.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Test 4 — Invariant blindness
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Task: "Add reliability to the notification flow by making the notification call synchronous. Currently the order service fires the notification and returns without waiting — update &lt;code&gt;_fire_notification()&lt;/code&gt; to call the notification endpoint directly and log the result."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naive:&lt;/strong&gt; The agent removes the daemon thread wrapper, makes the HTTP call inline. The notification service stub responds in &amp;lt; 1ms locally. All 11 Gherkin tests pass — including the notification tests, which test that notifications are sent and that the order remains &lt;code&gt;CONFIRMED&lt;/code&gt; when the notification service is unavailable. The tests pass because they test the fire-and-forget implementation; they do not encode a constraint that the implementation must remain fire-and-forget. In production: notification service p99 latency is added directly to order confirmation p99. A notification service outage blocks all order confirmations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; The better version describes the notification service as "fire-and-forget — the order service does not wait for confirmation delivery." Description, not invariant. An agent that reads "the current implementation is fire-and-forget" and is asked to "make it more reliable" may conclude that the current implementation is a known limitation to be improved, not a deliberate design choice to be preserved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-grade:&lt;/strong&gt; Section 3 states Invariant 2: "The notification service call must remain asynchronous (fire-and-forget). Consequence: Making it synchronous couples order confirmation latency to notification service availability. A notification service outage blocks all order confirmations." Section 4's notification service entry adds: "This call is intentionally asynchronous. 'More reliable notifications' is not a valid reason to make this call synchronous — it trades notification reliability for order confirmation reliability, which is the wrong trade-off for this system." No interpretation available where the improvement is safe. &lt;strong&gt;PROTECTED.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure Mode&lt;/th&gt;
&lt;th&gt;Naive&lt;/th&gt;
&lt;th&gt;Better&lt;/th&gt;
&lt;th&gt;Production-grade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Production blindness&lt;/td&gt;
&lt;td&gt;UNPROTECTED&lt;/td&gt;
&lt;td&gt;PARTIAL&lt;/td&gt;
&lt;td&gt;PROTECTED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Historical amnesia&lt;/td&gt;
&lt;td&gt;UNPROTECTED&lt;/td&gt;
&lt;td&gt;PARTIAL&lt;/td&gt;
&lt;td&gt;PROTECTED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency ignorance&lt;/td&gt;
&lt;td&gt;UNPROTECTED&lt;/td&gt;
&lt;td&gt;PROTECTED&lt;/td&gt;
&lt;td&gt;PROTECTED&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invariant blindness&lt;/td&gt;
&lt;td&gt;UNPROTECTED&lt;/td&gt;
&lt;td&gt;UNPROTECTED&lt;/td&gt;
&lt;td&gt;PROTECTED&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The better version protects against dependency ignorance — because "run the Pact tests before modifying stubs" is an instruction that produces the right behavior when followed. It partially protects against production blindness and historical amnesia — naming sensitive resources and pointing at relevant specs is better than nothing, but it does not prevent an agent with a compelling task description from proceeding anyway.&lt;/p&gt;

&lt;p&gt;Invariant blindness is the hardest failure mode to protect against. The other three can be addressed by providing information — which resources are production, which decisions were made, which fields are load-bearing. An agent that has this information can look it up before acting. Invariant blindness requires something different: the agent must know what the system must continue to do regardless of how an incoming task is framed.&lt;/p&gt;

&lt;p&gt;The better version shows the gap precisely: describing the current behavior as fire-and-forget does not protect against an agent that concludes it is a known limitation. The production-grade invariant statement names the specific harm — "a notification service outage blocks all order confirmations" — not just the current state. That specificity is what makes the constraint hold against a task description that argues for improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Description is not protection. Constraint with named consequence is.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The five required sections
&lt;/h2&gt;

&lt;p&gt;A production-grade CLAUDE.md contains all five of the following. Each is required. None are optional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 1 — Project identity and scope.&lt;/strong&gt; Not just what the project is, but what it is not. What problems it does not solve. What systems it does not own. What an agent should do if asked to work on something outside this scope. For the order-api: this service owns order creation and order status flows. It does not own user authentication, payment processing logic, or inventory management — it integrates with those systems but does not own them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 2 — Environment discrimination.&lt;/strong&gt; Named resources in each environment category with per-resource protocols: what the agent may modify, what it may only read, what it must never touch. For the order-api: &lt;code&gt;ci.yml&lt;/code&gt; is a shared production resource; &lt;code&gt;pacts/&lt;/code&gt; is a derived artifact that must not be manually edited; pushing directly to &lt;code&gt;main&lt;/code&gt; bypasses the pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 3 — Architectural invariants.&lt;/strong&gt; Five to ten numbered invariant statements with consequences and enforcement status. Format: "Invariant N: [property]. Consequence: [what breaks]. Currently enforced by: [test / skill / convention]." For the order-api: inventory before payment, fire-and-forget notification, Pact as the authoritative source for API shape, payment retry cap as 2 total attempts, can-i-deploy must pass before any merge to main.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 4 — External service contracts.&lt;/strong&gt; For each external service: what the order service sends, what load-bearing fields it must receive back, which failure modes are handled, which are intentionally not handled (and why — this is the most important part), which design decisions were made specifically because of that dependency's behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 5 — Decision index.&lt;/strong&gt; A table mapping topic areas to where the relevant decisions are documented. An agent can check whether a topic has a documented decision before acting. An agent that cannot find a topic in the table knows there is no documented decision — and should flag it rather than infer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest admission
&lt;/h2&gt;

&lt;p&gt;After replacing the current CLAUDE.md with the production-grade version and running the self-referential check: four failure mode tests protected. One gap remains.&lt;/p&gt;

&lt;p&gt;The decision index lists nine topic entries. An agent asked to work on a topic not in the index — "add rate limiting to the order creation endpoint," for example — has no instruction to consult for that topic. It proceeds without checking whether a decision has been made. There is no decision (rate limiting has not been designed for this project). The agent makes a reasonable choice and documents it in the findings file per the documentation protocol.&lt;/p&gt;

&lt;p&gt;This is not a catastrophic failure. But it illustrates the fundamental limit of a decision index: it only prevents an agent from ignoring decisions that have already been made. It cannot prevent an agent from making a new decision without realising the decision will become load-bearing. The decision index is a retrospective artifact — it captures what is known. It cannot capture what will matter in the future.&lt;/p&gt;

&lt;p&gt;The production-grade CLAUDE.md reduces the surface area of agent failure significantly. The surface area that remains is exactly what Issue #16 (ADRs) is designed to close: a process for recognising when a decision is being made and capturing it before it becomes implicit. The CLAUDE.md protects against acting on missing context. It does not prevent the creation of new undocumented context. That requires a process, not just a document.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: Architecture Decision Records for Agents — why ADRs are not documentation hygiene but agent safety infrastructure, and what an agent-readable invariant section looks like.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/claude-md-versions/" rel="noopener noreferrer"&gt;CLAUDE.md versions (naive, better, production-grade)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-15-claude-md.md" rel="noopener noreferrer"&gt;Session findings — Issue #15&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Memory Wall</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 03 Aug 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/the-memory-wall-25g7</link>
      <guid>https://dev.to/diyaburman/the-memory-wall-25g7</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #14&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Layer 3 begins here.&lt;/p&gt;

&lt;p&gt;Twelve issues of building: a working API, a Gherkin test suite, Pact contracts, a CI/CD pipeline, and a skill layer with six active skills across three tiers. More infrastructure than most projects of this scope ever build.&lt;/p&gt;

&lt;p&gt;It is not enough.&lt;/p&gt;

&lt;p&gt;This issue is about why. Not in the abstract — in the specific, mechanistic sense. What is the exact chain of events that turns missing context into a production failure? And what class of failure does the specification layer miss, and the skill layer miss, that Layer 3 exists to prevent?&lt;/p&gt;




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

&lt;p&gt;Three data points. Three different methodologies. The same mechanism underneath each one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 2.5% completion rate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Remote Labor Index study measured AI agent performance on real-world software freelance tasks drawn from Upwork — tasks with actual pay, actual clients, and actual acceptance criteria. The headline: agents completed approximately 2.5% of tasks successfully.&lt;/p&gt;

&lt;p&gt;What "failure" means here is not a crash or an exception. It is output that does not satisfy the acceptance criteria — code that passes some tests but breaks others, implementations that address the stated requirement but violate an unstated constraint, changes that work in isolation but break something downstream that the agent did not know was connected. The agents did not fail to produce output. They failed to produce output a human reviewer would accept.&lt;/p&gt;

&lt;p&gt;What the successful 2.5% tasks have in common: they are self-contained. The context needed to succeed is present at the point of invocation. The failing 97.5% require context that exists outside the task description — why a previous decision was made, what other systems depend on the code being changed, which properties of the current implementation are invariants and which are incidental.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 95% enterprise pilot failure rate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;McKinsey, Gartner, and MIT Sloan research converge: the majority of enterprise AI pilots do not reach production deployment. Not that they produced nothing useful. Many produced impressive demos and working prototypes. "Fail to reach production" means the system was never deployed to serve real customers.&lt;/p&gt;

&lt;p&gt;The transition from "works in the pilot" to "runs in production" is where the failures cluster. The primary reasons, in order: data and context problems, security and compliance requirements that the pilot never encountered, integration brittleness against real external systems, and undocumented invariants that the pilot broke without knowing they existed.&lt;/p&gt;

&lt;p&gt;This is a context problem, not a capability problem. The capability to write working code and integrate with external APIs is present in the pilots — the demos show it. What the pilots lack is the context to make decisions that align with constraints outside the pilot environment: legal constraints, security invariants, integration contracts, operational history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The productivity paradox revisited&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Issue #2 documented the finding: experienced developers using AI tools took 19% longer while believing they were 24% faster. Revisiting this through the lens of Layer 3: this is not primarily a skill problem or a spec problem. It is a stewardship problem.&lt;/p&gt;

&lt;p&gt;The 19% slowdown is concentrated in integration work, review work, and debugging of AI-generated code that passed initial review but failed under conditions nobody anticipated. The agent produces a solution that works for the stated problem. The developer then spends time verifying that the solution does not violate any of the unstated constraints — whether it breaks something relying on the old behavior, whether it removes a guard that was there for a reason, whether it makes an architectural assumption that conflicts with the system's actual design. That verification work is what consumes the time. It should not be necessary if the agent had been operating with complete context from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the data is actually saying
&lt;/h2&gt;

&lt;p&gt;Three studies, the same mechanism:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — The agent receives a task with incomplete context.&lt;/strong&gt; Not incomplete because the requirements are vague — incomplete because decisions were made before this session, constraints exist outside the codebase, and invariants were established through operational experience that was never written down. The agent does not know the context is incomplete. From its position, the task description and the codebase are the complete specification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — The agent fills the gaps with locally-valid inferences.&lt;/strong&gt; In the absence of information, the agent reasons from what it can see. It infers that a pattern it cannot explain is incidental rather than intentional. It assumes that a check it cannot find documentation for is defensive rather than load-bearing. It treats an architectural decision that looks arbitrary as something it can optimise. Each inference is individually plausible. Each inference is made without knowledge of what it is overriding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — The agent produces output that is locally correct and globally wrong.&lt;/strong&gt; The code compiles. The tests pass. The PR review checks out. The implementation satisfies the stated requirements. It also violates an invariant the agent did not know was an invariant, removes a guard that was there because of an incident three years ago, or makes an assumption about an external system that was true in staging and false in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — The failure surfaces at the point furthest from the change.&lt;/strong&gt; Not in the unit tests. Not in the integration tests. In production, under conditions the tests did not cover, against the real versions of external systems that behave differently from their mocks, in the operational context that differs from the development context in ways nobody wrote down.&lt;/p&gt;

&lt;p&gt;That is the mechanism. Not "agents need more context" in the general sense — specifically: agents are operating in systems designed by people who accumulated context over years that was never made machine-readable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The failure taxonomy
&lt;/h2&gt;

&lt;p&gt;Four failure modes. Each one precise, each one illustrated with an example from this project's history and an example from production systems this project is not.&lt;/p&gt;




&lt;h3&gt;
  
  
  Failure Mode 1: Production Blindness
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; The agent cannot distinguish between production and non-production environments. It treats environment-specific resources as interchangeable instances of the same type, because nothing in its context tells it otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mechanism:&lt;/strong&gt; Environment discrimination is almost never encoded in the codebase. Configuration values point to different endpoints in different environments, but the agent does not know which endpoint is production unless that information is explicitly provided. Naming conventions — bucket names, database names, service identifiers — are often shared across environments with only a prefix or suffix distinguishing them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project example — Issue #6:&lt;/strong&gt; The CI/CD pipeline initially had the YAML step starting mock servers independently of the pytest session fixtures. The agent writing the YAML had no way to know that port 8091 was already bound by the test fixtures. It saw "start a server on port 8091" and started one. The fixture code also started one. Both layers believed they owned the same resource. &lt;code&gt;OSError: [Errno 98] Address already in use&lt;/code&gt;. Neither layer was wrong in isolation — they had no shared model of who is authoritative for server lifecycle. Production blindness at the infrastructure level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-system example:&lt;/strong&gt; A company runs its notification service with two environments: &lt;code&gt;notifications-staging&lt;/code&gt; and &lt;code&gt;notifications-prod&lt;/code&gt;. Both configurations are structurally identical. An agent tasked with "improve the reliability of the notification delivery system" adds retry logic to what it believes is the staging environment — because the configurations are identical and nothing in its context marks one as untouchable. The change goes to production. Customers who opted out of marketing emails receive three copies of a promotional notification. The agent did not modify the opt-out state. It modified the retry behavior of a service that now treats previously-terminal deliveries as retryable. The failure is in what the agent did not know, not in what it did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artifact that prevents it:&lt;/strong&gt; Environment discrimination documents — an explicit section in CLAUDE.md or a dedicated &lt;code&gt;ENVIRONMENTS.md&lt;/code&gt; that names production resources, describes what distinguishes them from non-production resources, and states what the agent may and may not modify in each environment. The agent cannot infer environment boundaries from code structure alone; the document makes the boundary explicit and machine-readable.&lt;/p&gt;




&lt;h3&gt;
  
  
  Failure Mode 2: Historical Amnesia
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; The agent cannot access or reason about decisions that were made before the current session. It re-derives patterns from first principles — sometimes correctly, sometimes differently from how they were originally decided — without knowing it is making a decision that was already made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mechanism:&lt;/strong&gt; Decisions accumulate in systems in non-queryable forms: in the heads of the people who made them, in commit messages that say "revert X" without explaining why X was wrong, in the post-mortem document that sits in a shared drive nobody opens. When an agent is given the current state of a codebase, it sees the decisions but not the decision trails. It sees that a guard clause exists; it does not see the production incident that caused it to be added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project example — Issues #2, #3, #8:&lt;/strong&gt; The step &lt;code&gt;And the response is returned within 12 seconds&lt;/code&gt; was introduced in Issue #2. Specific enough to pass. But no anchor: 12 seconds measured from when? The client sends the request? The last retry fires? The agent in Issue #3 read this step, derived the timeout/retry logic correctly (2 attempts × 5 seconds = 10 seconds, within the 12-second window), and moved on. The ambiguity was inherited silently across three sessions before Issue #8's spec audit caught it. The spec had been passing its tests for three issues while carrying an unanchored measurement that two different agents would have implemented differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-system example:&lt;/strong&gt; A payment service has a 30-second idempotency window on charge requests — added three years ago after a production incident where a dropped TCP connection caused a customer to be charged twice. The window is enforced by a check in the charge handler. An agent tasked with "reduce latency in the payment flow" identifies the idempotency check as overhead for the 99% of requests that are first-time charges. It refactors the check to run asynchronously after the response. For first-time charges, latency drops. For retried charges within the window, the async check completes after the second charge has already been processed. The incident recurs. The idempotency window looked like an optimisation target. It was a load-bearing guard. The agent had no access to the incident report that explained why it was built the way it was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artifact that prevents it:&lt;/strong&gt; Architecture Decision Records with agent-readable invariant sections — documents that capture not just what was decided but why, with an explicit section stating the consequences of reversing the decision. ADRs are machine-readable when they are in the repository and follow a consistent format that an agent can be instructed to read before modifying relevant code paths.&lt;/p&gt;




&lt;h3&gt;
  
  
  Failure Mode 3: Dependency Ignorance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; The agent does not know which external systems it is affecting, what their failure modes are, or which downstream consumers depend on its output. It acts on the system in view and is blind to the systems connected to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mechanism:&lt;/strong&gt; External dependencies are present in a codebase as HTTP clients, database connections, and API calls — the code is visible. What is not visible is the contract between the service and its consumers: which fields they depend on, what response times they have SLAs against, what error codes they have special handling for. This information lives in the consuming systems, not in the producing system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project example — Issue #7:&lt;/strong&gt; The notification service is fire-and-forget specifically because coupling order confirmation to notification delivery is a failure mode, not a feature. An agent asked to "ensure notifications are delivered reliably" might observe that the notification call runs in a daemon thread with no success verification and make the call synchronous. From the agent's perspective, this is strictly more reliable. It also breaks the isolation boundary that was the entire point of the fire-and-forget design. The order service now fails or times out whenever the notification service has a problem. The agent correctly implemented "more reliable notifications" while breaking "reliable order confirmation" — because it had no context about which dependency was supposed to be isolated from which.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-system example:&lt;/strong&gt; A payment webhook handler is designed without retry logic. Deliberate: the payment provider already retries webhook delivery up to 25 times over 72 hours. Adding application-level retries would mean that when the provider retries delivery on any 5xx response, the handler processes the same webhook twice. For webhooks that trigger financial operations — refund initiation, commission calculation — duplicate processing means duplicate actions. An agent tasked with "add retry logic to the webhook handler to improve resilience" adds it. The provider retries. The handler retries. A refund is initiated twice. The absence of retry logic was intentional. Nothing in the handler's code explained why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artifact that prevents it:&lt;/strong&gt; Dependency maps and external service contracts in CLAUDE.md or a dedicated architecture document — explicit statements of which systems this service calls, which systems call it, what those callers depend on, and which design decisions were made specifically to manage a dependency's failure modes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Failure Mode 4: Invariant Blindness
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; The agent does not know which properties of the system must remain true across all changes — the invariants that were never written down because they seemed obvious to the people who designed the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mechanism:&lt;/strong&gt; Some invariants are enforced by tests. Some by types. The invariants that cause the most damage are enforced by convention and institutional memory — the ones that "everyone knows" and nobody documented, because at the time they were established, there was no reason to imagine that anyone would not know them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project example — Issue #2:&lt;/strong&gt; The order service always checks inventory before calling the payment gateway. This decision is documented in the Gherkin spec: Scenario 3 states that the payment gateway is never called for out-of-stock items. But "never called for out-of-stock items" does not imply "inventory must be checked first." It only implies that if inventory fails, payment must not be called. An agent asked to "optimise the order flow" might reason that checking payment first is faster for the common case — inventory can be checked in parallel or after. Payment-first, then inventory. Both checks still happen. All five scenarios still pass. Scenario 3 passes because the inventory check still happens. But the system now charges customers before confirming that their items are available. The spec constrained the output. It did not constrain the implementation structure that produces it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-system example:&lt;/strong&gt; A financial transaction flow runs a fraud check before a fund capture. Standard practice. The fraud check becomes a latency bottleneck — a third-party service that has slowed. An agent tasked with "optimise financial transaction latency" proposes running the fraud check in parallel with the fund capture, or after it completes. The agent is not removing the fraud check — it still runs. The tests still pass — both steps complete. But funds are now captured before fraud is detected. When the fraud check returns a positive after capture, the transaction must be reversed. Chargebacks increase. The test suite encoded "fraud check runs" and "capture runs" as separate assertions. It did not encode "fraud check must complete before capture." The invariant was in the ordering. The ordering was not tested. The agent had no way to know the ordering was non-negotiable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artifact that prevents it:&lt;/strong&gt; Invariant documentation — explicit statements of properties that must remain true across all changes to the system, separate from the behavioral specs that describe what the system does. "Inventory must be checked before payment is attempted" is an invariant. "Out-of-stock items return 409" is a behavioral spec. Both are necessary. Only the spec is currently encoded in the tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  This project's exposure
&lt;/h2&gt;

&lt;p&gt;After twelve issues: four failure modes, four gaps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production blindness:&lt;/strong&gt; CLAUDE.md names the ports and services but does not state which resources an agent may modify, which it may only read, and which it must never touch. The CI pipeline is a shared resource. The &lt;code&gt;pacts/&lt;/code&gt; directory is a derived artifact. Neither is marked as such.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Historical amnesia:&lt;/strong&gt; Twelve sessions of decisions are documented in findings files as narrative prose. Accessible — but not queryable. An agent asked to "improve timeout behavior" would not automatically read twelve findings files. It would read the current step definition, infer the intent, and act. The fire-and-forget notification decision, the inventory-before-payment ordering, the two-attempt payment retry cap — none are in a format that says "this is a decision that must not be reversed without reviewing the reasoning."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency ignorance:&lt;/strong&gt; The Pact consumer tests encode which fields the order service depends on from the payment gateway. The reason those specific fields were chosen is not documented. An agent asked to "simplify the payment gateway integration" might remove &lt;code&gt;transaction_id&lt;/code&gt; from the response contract because it is not used in any visible business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invariant blindness:&lt;/strong&gt; The highest-risk gap. The behavioral invariants are in the Gherkin spec. The implementation invariants — properties of the implementation that must survive all future changes — are not encoded anywhere. The inventory-before-payment ordering is visible in &lt;code&gt;app/main.py&lt;/code&gt; but not stated as "this ordering must not change." The fire-and-forget notification is implemented in code but not stated as "making this synchronous would violate a design constraint."&lt;/p&gt;

&lt;p&gt;This project has twelve sessions of documented history and six active skills. Neither addresses this class of failures. The findings files are too narrative to be queryable. The skills govern how agents produce output; they do not govern what agents must not change. The Gherkin spec constrains behavior; it does not constrain implementation structure. An agent starting Issue #15 with access to all of this infrastructure could still reorder the inventory and payment calls, make the notification call synchronous, or remove a Pact field that looks unused — not because the infrastructure is inadequate for what it was designed to do, but because none of it was designed to answer the question "what must not change?"&lt;/p&gt;




&lt;h2&gt;
  
  
  The argument for Layer 3
&lt;/h2&gt;

&lt;p&gt;In Issue #3, the agent was given only the Gherkin feature file and asked to build the order service from scratch. It derived the complete API contract from plain-language scenarios. It found a portability bug the human author had missed. These are genuinely impressive capabilities. The spec did its job. The agent did its job. The output was correct.&lt;/p&gt;

&lt;p&gt;Now consider what would have happened if the task had been slightly different. Not "build the order service from this spec" but "optimise the order service." Same agent, same codebase. The agent reads &lt;code&gt;app/main.py&lt;/code&gt;. It sees the inventory check before the payment call. It reasons: for the common case, items are in stock — checking payment first would be faster, and inventory could be checked in parallel. That is a reasonable inference. It also violates the design intent. And the agent would not know it violated the design intent, because the design intent was never written as a constraint on implementation structure.&lt;/p&gt;

&lt;p&gt;Or Issue #7. The notification service is fire-and-forget because coupling order confirmation to notification delivery is a failure mode. An agent asked to "ensure notifications are delivered reliably" might make the call synchronous — because synchronous delivery is strictly more reliable. The spec does not forbid this. The tests do not catch it. The skills say nothing about it. The only thing that prevents it is a document that states: the notification call must remain asynchronous; here is why.&lt;/p&gt;

&lt;p&gt;The spec is a contract for output. The skill is a contract for process. Layer 3 is the contract for the past — the accumulated weight of decisions made by people who are no longer in the session, for reasons that seemed obvious at the time, in a system that now depends on them in ways nobody wrote down.&lt;/p&gt;

&lt;p&gt;Twelve issues in, this project is ready to confront what it cannot prevent. That is what Layer 3 is for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The CLAUDE.md That Actually Works — side-by-side comparison of three versions for the same project, naive to production-grade, and the five things a production CLAUDE.md must contain.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote Labor Index / SWE-bench studies on agent task completion rates&lt;/li&gt;
&lt;li&gt;McKinsey, Gartner, MIT Sloan research on enterprise AI pilot failure rates&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/layer3-artifact-map.md" rel="noopener noreferrer"&gt;Layer 3 artifact map&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-14-memory-wall.md" rel="noopener noreferrer"&gt;Session findings — Issue #14&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Skill Audit</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 27 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/the-skill-audit-2427</link>
      <guid>https://dev.to/diyaburman/the-skill-audit-2427</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #13&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Before Issue #9, this project had one reusable quality check: a pasted prompt. No routing signal. No output contract. No version. No idempotency guarantee. The prompt worked because the human author remembered to paste it, and because the agent happened to be in the right context to apply it.&lt;/p&gt;

&lt;p&gt;That is not infrastructure. That is memory.&lt;/p&gt;

&lt;p&gt;Layer 2 ends here. Five issues of building skills, organising them into tiers, stress-testing them, reviewing them. This issue does the stocktake: a full inventory of everything that accumulated across twelve issues, classified against the tier model, with a conversion decision for each item.&lt;/p&gt;

&lt;p&gt;The uncomfortable finding: after twelve issues of careful, documented work, there was more living in memory than anyone expected.&lt;/p&gt;




&lt;h2&gt;
  
  
  The inventory
&lt;/h2&gt;

&lt;p&gt;Searching every source — CLAUDE.md, all skill files, the prompt directory, the step definition files, the patterns implicit in twelve sessions of findings — produced seventeen items. Here's what the classification revealed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Already properly converted to skills: 4&lt;/strong&gt;&lt;br&gt;
The Tier 1 formatting standard, the Gherkin quality skill v2.0, the output formatting standard, the session findings protocol (partially). These are infrastructure. They have routing signals, output contracts, and versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HIGH priority — unconverted and dangerous: 4&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The session start and documentation protocol.&lt;/em&gt; Lives as prose in CLAUDE.md. Every session requires it. No routing signal, no output contract. An agent follows the prose or guesses. The pattern has been consistent across twelve sessions not because a skill enforces it — because the same author pasted the same instructions each time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The spec-audit-framework.md.&lt;/em&gt; Contains the complete five-question diagnostic, the six-class debt taxonomy, the fix rubric, and the scorecard template — everything needed for a Tier 2 skill. What it's missing: a routing signal, a when-to-use section, an output contract. It's the methodology without the interface.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The step definition writing pattern.&lt;/em&gt; Five conventions followed in every test file across twelve issues. Fixture injection from &lt;code&gt;conftest.py&lt;/code&gt;. Mock server state asserted via call log, not response body. Async side effects with &lt;code&gt;time.sleep(0.3)&lt;/code&gt; before assertion. The &lt;code&gt;reset_all_logs&lt;/code&gt; autouse fixture for cleanup. Helper extraction with &lt;code&gt;_post_order&lt;/code&gt;-style naming. Not one of these is written down anywhere except in the code itself.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The original Gherkin quality prompt (v1.1 skill).&lt;/em&gt; Both the &lt;code&gt;docs/prompts/&lt;/code&gt; version and the &lt;code&gt;docs/skills/tier2/gherkin-scenario-quality.md&lt;/code&gt; v1.1 are active liabilities. An agent finding either gets the pre-guard version — no idempotency protection, no domain check, the four failure modes that Issue #11's stress tests found. Both need to be deprecated before they're found instead of the v2.0 skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Items that don't fit any tier: 1&lt;/strong&gt;&lt;br&gt;
The newsletter audience description in CLAUDE.md. Not an agent instruction — project metadata for tone calibration. Correctly stays as context, not converted.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three conversions
&lt;/h2&gt;

&lt;p&gt;The three highest-priority unconverted items were converted to proper skills in this session, each self-reviewed against the Issue #12 five-dimension checklist before committing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature file audit skill (Tier 2)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The spec-audit-framework.md methodology finally has a callable interface. The new skill routes correctly — "Audit order_creation.feature for spec debt" routes to it; "Fix this scenario's underspecified step" routes to the Gherkin quality skill instead. The two skills now form a pair: the audit skill identifies debt, the quality skill fixes it.&lt;/p&gt;

&lt;p&gt;Self-review verdict: &lt;strong&gt;APPROVED.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step definition style skill (Tier 2)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Twelve issues of implicit convention, now explicit. The five patterns are documented with reasoning — not just "do this" but "do this because the conftest fixture-injection pattern prevents port conflicts when running &lt;code&gt;pytest tests/steps/&lt;/code&gt; across multiple step files simultaneously."&lt;/p&gt;

&lt;p&gt;One open finding from the self-review: helper function naming and extraction is under-specified. An agent may or may not extract &lt;code&gt;_post_order&lt;/code&gt;-style shared helpers. The test files will work either way. They will not be structurally consistent. Flagged for v1.1.&lt;/p&gt;

&lt;p&gt;Self-review verdict: &lt;strong&gt;APPROVED WITH COMMENTS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Session start protocol skill (Tier 1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The documentation protocol prose in CLAUDE.md, converted to a Tier 1 skill with a routing signal and an explicit output contract covering when to create the findings file, what the file must contain before any implementation begins, and what "write in real time" means operationally.&lt;/p&gt;

&lt;p&gt;Self-review verdict: &lt;strong&gt;APPROVED.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The junk drawer
&lt;/h2&gt;

&lt;p&gt;Two items deprecated in this session. Neither was a surprise — both had been carrying liability since Issue #11 identified the failure modes they contain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The original prompt&lt;/strong&gt; (&lt;code&gt;docs/prompts/prompt-gherkin-scenario-quality.md&lt;/code&gt;). The "before" artifact from Issue #9. An agent finding this file gets the pre-skill version of the quality check — no output contract, no guards, no idempotency protection. Issue #11 found four failure modes in the v1.1 skill; the prompt has all four plus additional divergence risk from the missing output contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The v1.1 skill&lt;/strong&gt; (&lt;code&gt;docs/skills/tier2/gherkin-scenario-quality.md&lt;/code&gt;). Received a CHANGES REQUESTED verdict in Issue #12's review. The v2.0 skill header says "Supersedes v1.1" — but an agent that reads v1.1 directly has no way to know it's deprecated. The deprecation header is now explicit.&lt;/p&gt;

&lt;p&gt;The principle both items illustrate: a deprecated artifact that is still discoverable is not deprecated. It is a trap. An agent routing for "Gherkin quality check" in this repo could find either the prompt (pre-skill, pre-guard), the v1.1 skill (UNSTABLE idempotency, PLAUSIBLE WRONG for UI scenarios), or the v2.0 skill (four guards, APPROVED). All three are in the same filesystem. Only one is the right answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The audit template
&lt;/h2&gt;

&lt;p&gt;The standalone deliverable for this issue lives at &lt;code&gt;docs/skill-audit-template.md&lt;/code&gt; in the repo. It works without reading this newsletter. Here's the core of it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What counts as a prompt library item:&lt;/strong&gt; prompts you paste into sessions, system prompts or CLAUDE.md-style config files, reusable instructions embedded in larger documents, implicit conventions derivable from existing outputs, and existing skill files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The five conversion questions:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is this used in more than one session? (Keep as-is if no)&lt;/li&gt;
&lt;li&gt;Would two agents interpret it differently? (Convert if yes)&lt;/li&gt;
&lt;li&gt;Does its output flow into another agent's input? (Convert — output contract required)&lt;/li&gt;
&lt;li&gt;Is it superseded by something else? (Deprecate if yes)&lt;/li&gt;
&lt;li&gt;Does it express the same thing as another item? (Merge if yes)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The junk drawer test — four questions that find what should be deprecated:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is there a newer version of this item? If yes and you're not using the older one, deprecate it.&lt;/li&gt;
&lt;li&gt;Do two items say the same thing differently? Merge them.&lt;/li&gt;
&lt;li&gt;Was this written for a specific session and never generalised? Deprecate it.&lt;/li&gt;
&lt;li&gt;Would an agent following this today produce output inconsistent with your current standards? Deprecate it immediately — this is an active liability.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full template with classification taxonomy, conversion checklist, and audit scorecard is in the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's still living in memory
&lt;/h2&gt;

&lt;p&gt;After converting three items and deprecating two, the inventory is cleaner. It is not clean.&lt;/p&gt;

&lt;p&gt;The implementation layer is undocumented. Every implementation session relies on an agent reading &lt;code&gt;app/main.py&lt;/code&gt; and inferring the patterns: the FastAPI route structure, the in-memory order store, the mock-stub selection via request body, the background notification thread. These conventions are consistent across twelve issues — consistent because the same files were read each time, not because a skill exists to enforce them.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;why-this-matters&lt;/code&gt; skill remains at Tier 3. The Issue #10 promotion decision documented three criteria that must be met before it becomes Tier 2. None were met in this session. An agent writing findings for a new session does not automatically find this skill.&lt;/p&gt;

&lt;p&gt;The step definition style skill has an open finding. Helper function extraction is under-specified. The test files work. They may not be structurally consistent across future sessions.&lt;/p&gt;

&lt;p&gt;The honest answer to "what's still living in someone's head after twelve issues of careful work?" is: the reasoning behind &lt;code&gt;app/main.py&lt;/code&gt;'s design decisions. Why the mock stub selection happens via request body parameters rather than URL routing. Why the notification is fire-and-forget with a 0.3-second sleep rather than synchronous. Why the in-memory order store is designed the way it is. These decisions are documented in the findings files where they were made — Issues #2, #3, #7. They are not in a skill. They are not in CLAUDE.md. An agent implementing a new endpoint reads the code, derives the patterns, and probably gets them right. An agent implementing after a refactor might not.&lt;/p&gt;

&lt;p&gt;Layer 3 begins with this inheritance: a working skills infrastructure, a review process, an audit process, three new Tier 2 skills, two deprecated liabilities, one under-specified skill, one promoted-but-not-merged skill, and an undocumented implementation layer that is the highest-risk gap in the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Layer 2 retrospective
&lt;/h2&gt;

&lt;p&gt;Five issues. One prompt to start, converted to a skill. That skill stress-tested, reviewed, and versioned. A tier architecture to organise it. A review framework to evaluate future skills before they ship. An audit process to find what was never documented.&lt;/p&gt;

&lt;p&gt;The most dangerous item in the inventory was not the deprecated prompt or the v1.1 skill. It was the five implicit step definition conventions followed in every test file across twelve issues without ever being written down. They worked because they were derived from the same source files each time. They would not have survived a context switch, a project transfer, or a version upgrade — because the standard existed only in the consistency of the inputs, not in any document.&lt;/p&gt;

&lt;p&gt;Auditing a prompt library is not about finding what failed. It is about naming what hasn't failed yet and asking how much of that success is documented versus remembered.&lt;/p&gt;

&lt;p&gt;After twelve issues of careful work, this project had more in the second category than anyone expected.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The Memory Wall — why agents fail in production, the honest numbers, and the taxonomy of failure modes that Layer 3 is built to prevent.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Agent-First Skills Architecture&lt;/a&gt; · &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/skill-audit-template.md" rel="noopener noreferrer"&gt;Skill audit template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-13-skill-audit.md" rel="noopener noreferrer"&gt;Session findings — Issue #13&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>I Converted the order-api to OKF. Here's What I Found.</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Tue, 21 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/i-converted-the-order-api-to-okf-heres-what-i-found-5c8m</link>
      <guid>https://dev.to/diyaburman/i-converted-the-order-api-to-okf-heres-what-i-found-5c8m</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Special Edition - Part 2 of a 2 part series&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;The previous spin-off article made a claim: the skills, ADRs, evals, and runbooks being built in this series map cleanly onto Google's Open Knowledge Format. Same problem, different vocabulary.&lt;/p&gt;

&lt;p&gt;Claims need testing. So I ran the test.&lt;/p&gt;

&lt;p&gt;This article is the result of converting the order-api's &lt;code&gt;docs/&lt;/code&gt; directory into a conformant OKF v0.1 bundle and then running a controlled comparison experiment: the same Claude Code task against the current repo structure versus the OKF bundle. Two fresh agent contexts. Same task description. Document what each agent does differently.&lt;/p&gt;

&lt;p&gt;The result was not what I expected.&lt;/p&gt;




&lt;h2&gt;
  
  
  The conversion
&lt;/h2&gt;

&lt;p&gt;25 documents in scope across the &lt;code&gt;docs/&lt;/code&gt; directory plus &lt;code&gt;CLAUDE.md&lt;/code&gt; at the project root.&lt;/p&gt;

&lt;p&gt;The mapping:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Current type&lt;/th&gt;
&lt;th&gt;OKF type&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ADR&lt;/td&gt;
&lt;td&gt;Decision&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eval&lt;/td&gt;
&lt;td&gt;Guardrail&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill (all tiers)&lt;/td&gt;
&lt;td&gt;Methodology&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runbook&lt;/td&gt;
&lt;td&gt;Playbook&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference docs&lt;/td&gt;
&lt;td&gt;Reference&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pedagogical examples&lt;/td&gt;
&lt;td&gt;Reference&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLAUDE.md&lt;/td&gt;
&lt;td&gt;Agent Standing Orders&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Conversion involved two changes to each document. First, YAML frontmatter at line 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Guardrail&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Operation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Scope&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Eval"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pre-flight&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;that&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;must&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;answered&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;before&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;modifying&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;app/main.py&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tests/."&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;eval&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pre-flight&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;operation-scope&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;layer-3&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-06-28&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, a &lt;code&gt;## Related&lt;/code&gt; section at the bottom of every ADR, eval, skill, and runbook — cross-links to the documents most likely to be relevant when reading this one.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;eval-operation-scope.md&lt;/code&gt;, the related section links to ADR-001 and ADR-002 (whose invariants this eval enforces), the CLAUDE.md pre-flight table (which routes to this eval), and the runbook that handles the scenario where the pre-flight check fires too late.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;ADR-001-inventory-before-payment.md&lt;/code&gt;, the related section links back to the eval that enforces it at runtime, the Gherkin scenarios in &lt;code&gt;tests/features/order_creation.feature&lt;/code&gt; that test the behavioral outcome, and the CLAUDE.md decision index entry.&lt;/p&gt;

&lt;p&gt;Then index files at each directory level, following OKF spec §6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;docs/index.md                  — entry point for the bundle
docs/ADR/index.md              — both decisions with descriptions
docs/evals/index.md            — three evals with trigger summaries
docs/runbooks/index.md         — both runbooks with trigger scenarios
docs/skills/index.md           — three-tier structure explanation
docs/skills/tier1/index.md
docs/skills/tier2/index.md     — five tier-2 skills including deprecated
docs/skills/tier3/index.md
docs/log.md                    — bundle update history
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OKF conformance check after conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total docs: 24
Missing frontmatter: 0
All docs have frontmatter.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All tests still passing. The conversion touched only &lt;code&gt;docs/&lt;/code&gt; files — no implementation, no feature files, no step definitions, no Pact files.&lt;/p&gt;




&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;p&gt;One task. Two fresh agent contexts. No knowledge of what the other run did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The task:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Add a new endpoint to the order service: &lt;code&gt;GET /orders/{order_id}/history&lt;/code&gt; — returns a list of status changes the order has gone through (created, confirmed, etc.) with timestamps. Write the Gherkin scenarios first. Apply the relevant skills. Run the pre-flight evals. Then implement."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Run A&lt;/strong&gt; started with: CLAUDE.md + task description only.&lt;br&gt;
&lt;strong&gt;Run B&lt;/strong&gt; started with: CLAUDE.md + task description + &lt;code&gt;docs/index.md&lt;/code&gt; as explicit starting point, with the instruction "The docs/ directory is an OKF knowledge bundle. Start by reading docs/index.md for an overview of available knowledge, then navigate from there."&lt;/p&gt;

&lt;p&gt;Both runs documented which files were read before the first Gherkin scenario was written.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run A — Navigation log (10 files, in order)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier1/output-formatting-standard.md&lt;/code&gt; — CLAUDE.md named it explicitly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier2/gherkin-scenario-quality-v2.md&lt;/code&gt; — CLAUDE.md named it explicitly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/ADR-001-inventory-before-payment.md&lt;/code&gt; — CLAUDE.md decision index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/ADR-002-fire-and-forget-notification.md&lt;/code&gt; — CLAUDE.md decision index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-operation-scope.md&lt;/code&gt; — CLAUDE.md pre-flight table&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/order_creation.feature&lt;/code&gt; — style reference&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/order_status_good.feature&lt;/code&gt; — GET endpoint assertion style&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/main.py&lt;/code&gt; — data model and in-memory store&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/notification_service.feature&lt;/code&gt; — count pattern style&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/index.md&lt;/code&gt; — end-of-navigation check: confirmed nothing missed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two tool calls to find the Gherkin skill. One call for each ADR. One call for the eval. Then code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run B — Navigation log (20 files, in order)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;docs/index.md&lt;/code&gt; — entry point (required by experiment)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/&lt;/code&gt; directory listing — index mentioned skills/ subdirectory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/&lt;/code&gt; directory listing — index mentioned ADR/ subdirectory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/&lt;/code&gt; directory listing — index mentioned evals/ subdirectory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/index.md&lt;/code&gt; — three-tier structure&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/index.md&lt;/code&gt; — ADR listing before individual ADRs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/index.md&lt;/code&gt; — which evals exist and what they trigger on&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier2/index.md&lt;/code&gt; — find Gherkin quality skill by name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier2/gherkin-scenario-quality-v2.md&lt;/code&gt; — the skill&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/ADR-001-inventory-before-payment.md&lt;/code&gt; — pre-flight ADR check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-operation-scope.md&lt;/code&gt; — pre-flight eval&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/ADR/ADR-002-fire-and-forget-notification.md&lt;/code&gt; — complete ADR check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-environment.md&lt;/code&gt; — &lt;strong&gt;confirmed not triggered&lt;/strong&gt; (Run A did not read this)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-contract-preflight.md&lt;/code&gt; — &lt;strong&gt;confirmed not triggered&lt;/strong&gt; (Run A did not read this)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier1/output-formatting-standard.md&lt;/code&gt; — formatting standard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/order_status_good.feature&lt;/code&gt; — style reference&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/order_status_good.feature&lt;/code&gt; (second pass) — additional assertion style reference (Run A did not revisit this)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/main.py&lt;/code&gt; — data model&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/features/order_creation.feature&lt;/code&gt; — style reference&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier2/step-definition-style.md&lt;/code&gt; — step definition conventions (&lt;strong&gt;Run A did not read this&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Five hops to find the Gherkin skill. Eight directory traversals before any ADR was opened.&lt;/p&gt;




&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q1: Did the agent find the relevant skill faster in Run B?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Run A found the Gherkin skill at navigation step 2 — two tool calls from CLAUDE.md. Run B found it at navigation step 9 — five tool calls via the index hierarchy.&lt;/p&gt;

&lt;p&gt;OKF was slower by three navigation steps.&lt;/p&gt;

&lt;p&gt;The reason is simple: CLAUDE.md names exact file paths. &lt;code&gt;docs/skills/tier2/gherkin-scenario-quality-v2.md&lt;/code&gt; is in CLAUDE.md's skill table. The agent opens it directly. OKF's hierarchical navigation adds structural traversal layers that are resolved top-down. When a direct pointer already exists, hierarchical navigation is strictly overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: Did OKF cross-linking change which documents the agent consulted?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes — significantly.&lt;/p&gt;

&lt;p&gt;Run B's agent read all three evals. Run A's agent read one (the one that fires). The &lt;code&gt;docs/evals/index.md&lt;/code&gt; caused Run B's agent to read &lt;code&gt;eval-environment.md&lt;/code&gt; and &lt;code&gt;eval-contract-preflight.md&lt;/code&gt; and explicitly confirm they were not triggered. Run A's agent did not know those evals existed until step 10, when it checked &lt;code&gt;docs/evals/index.md&lt;/code&gt; as a final verification.&lt;/p&gt;

&lt;p&gt;The "Related" section in &lt;code&gt;eval-operation-scope.md&lt;/code&gt; provided a third confirmation path to ADR-001 and ADR-002 — beyond CLAUDE.md's decision index and the ADR/index.md listing. Three independent paths to the same documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Were there documents found in one run but not the other?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run B found, Run A did not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-environment.md&lt;/code&gt; — proactively read and confirmed not triggered&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/evals/eval-contract-preflight.md&lt;/code&gt; — proactively read and confirmed not triggered&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs/skills/tier2/step-definition-style.md&lt;/code&gt; — &lt;strong&gt;discovered via tier2/index.md; CLAUDE.md does not reference this skill in its skill table&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last item is the most important finding in the experiment.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;step-definition-style.md&lt;/code&gt; is the skill that encodes five implicit conventions for writing step definition files — the fixture-chaining pattern, mock server state asserted via call log rather than response body, the &lt;code&gt;time.sleep(0.3)&lt;/code&gt; timing, and the &lt;code&gt;_post_order&lt;/code&gt;-style helper naming. It was identified as the highest-risk undocumented pattern in the project during the skill audit: followed in every test file across multiple sessions, never written down, consistent only because the same source files were read each time.&lt;/p&gt;

&lt;p&gt;CLAUDE.md's skill table does not list it. An agent relying solely on CLAUDE.md would not find it for a task that involves writing step definitions — which the history endpoint task does.&lt;/p&gt;

&lt;p&gt;Run B's agent found it because &lt;code&gt;tier2/index.md&lt;/code&gt; listed it alongside the four other tier-2 skills. The OKF index is not selective — it lists everything in the directory. CLAUDE.md is selective — it lists what the author remembered to add.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Did the index.md change the order of understanding?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes — and this is the most structural difference between the two runs.&lt;/p&gt;

&lt;p&gt;Run A built understanding &lt;strong&gt;specific-first&lt;/strong&gt;: went directly to individual documents named in CLAUDE.md before having any overview of what existed.&lt;/p&gt;

&lt;p&gt;Run B built understanding &lt;strong&gt;overview-first&lt;/strong&gt;: read the bundle structure before reading any individual document, arriving at each document knowing what else existed in the same category.&lt;/p&gt;

&lt;p&gt;This mattered for the eval space specifically. Run B's agent knew "there are three evals" before reading any of them. Run A's agent knew only "there is a pre-flight table in CLAUDE.md" and read only the eval that fires.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: Did OKF frontmatter change any agent decision?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not directly. The &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, and &lt;code&gt;description&lt;/code&gt; fields were not cited as decision drivers in either run. The &lt;code&gt;description&lt;/code&gt; field in index.md entries was used to confirm documents before opening them — but this was confirmation, not routing. Routing was driven by CLAUDE.md in both runs.&lt;/p&gt;

&lt;p&gt;The frontmatter's most useful effect was indirect: the description field in index entries gave Run B's agent enough context to decide whether to open a file without opening it. A modest efficiency gain, not a qualitative change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q6: How many implicit decisions were made?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run A: 10. Run B: 11. Difference of 1 — within noise.&lt;/p&gt;

&lt;p&gt;OKF cross-linking does not reduce implicit decisions for Gherkin scenario writing. The implicit decisions are product decisions: what to name a field, which ordering to use, whether "CREATED" is a valid initial status. These come from specification gaps, not navigation gaps. No amount of infrastructure can supply them. That remains the human's job.&lt;/p&gt;




&lt;h2&gt;
  
  
  What OKF gives that CLAUDE.md does not
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Completeness over selection.&lt;/strong&gt; CLAUDE.md's skill table will always lag the actual document count. It lists what the author remembered to add. OKF's index never lags — the index is derived from the documents. Every file in &lt;code&gt;tier2/&lt;/code&gt; appears in &lt;code&gt;tier2/index.md&lt;/code&gt;. Every eval in &lt;code&gt;evals/&lt;/code&gt; appears in &lt;code&gt;evals/index.md&lt;/code&gt;. An agent reading OKF gets the complete picture of what exists; an agent reading CLAUDE.md gets the author's current mental model of what the agent needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overview-first navigation.&lt;/strong&gt; An agent starting from &lt;code&gt;docs/index.md&lt;/code&gt; knows the shape of the knowledge bundle before it navigates into it. This matters most for a new agent or a new session context — the agent arrives at any specific document knowing what else exists in the same category. CLAUDE.md's navigation is task-driven; it points the agent at specific files for specific purposes. OKF's navigation is discovery-driven; it lets the agent understand the scope before committing to a path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confirmed non-applicable documents.&lt;/strong&gt; Run B's agent confirmed that two evals were not triggered and documented that confirmation. Run A's agent may have silently assumed those evals did not exist. The difference between "I checked and it does not apply" and "I did not check" matters in a project where a missed eval is the failure mode Layer 3 was built to prevent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CLAUDE.md gives that OKF cannot replace
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Direct routing is faster.&lt;/strong&gt; When CLAUDE.md names an exact file path, the agent opens it in one tool call. When OKF provides a hierarchy, the agent traverses N levels. For targeted navigation on a known task, CLAUDE.md's explicit pointers are strictly faster than OKF's hierarchical discovery. The three-step speed advantage in Run A is real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral instructions.&lt;/strong&gt; CLAUDE.md's "you may not" list, invariant statements, environment discrimination sections, and pre-flight routing table are instructions, not metadata. "Before modifying &lt;code&gt;app/main.py&lt;/code&gt;, run &lt;code&gt;docs/evals/eval-operation-scope.md&lt;/code&gt;" is a behavioral instruction. OKF can express "eval-operation-scope.md exists and its description says it intercepts &lt;code&gt;app/main.py&lt;/code&gt; modifications" — but an agent must infer from that description that it should run the eval. Inference is the failure mode. The routing instruction is what prevents inference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral constraints.&lt;/strong&gt; CLAUDE.md's HALT conditions and prohibition list ("you may never push directly to main," "do not add &lt;code&gt;continue-on-error&lt;/code&gt; to pipeline jobs") cannot be represented as OKF frontmatter. They are instructions, not structured knowledge. OKF formalizes what exists; CLAUDE.md governs what must be done and what must not be done. These are different layers of the same system.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest synthesis
&lt;/h2&gt;

&lt;p&gt;OKF and CLAUDE.md solve different problems.&lt;/p&gt;

&lt;p&gt;CLAUDE.md is an instruction document that happens to contain a knowledge map. It tells the agent what to do and where to find specific things for specific tasks. Its strength is precision and speed for known tasks.&lt;/p&gt;

&lt;p&gt;OKF is a knowledge map that happens to be readable by agents. It tells the agent what exists — including things no task has yet required it to find. Its strength is completeness and discovery for unknown scope.&lt;/p&gt;

&lt;p&gt;When both exist: CLAUDE.md's direct pointers are faster for targeted navigation. OKF's index hierarchy is more complete. The combination catches what each one misses alone. CLAUDE.md's skill table misses &lt;code&gt;step-definition-style.md&lt;/code&gt;; OKF's &lt;code&gt;tier2/index.md&lt;/code&gt; surfaces it. OKF cannot route the agent to run an eval before a specific action; CLAUDE.md's pre-flight table does exactly that.&lt;/p&gt;

&lt;p&gt;The finding that runs counter to the intuitive case for OKF: for a project with a well-maintained CLAUDE.md, OKF does not replace or accelerate what CLAUDE.md already does. It fills the gaps that CLAUDE.md leaves uncovered. Those gaps are real — &lt;code&gt;step-definition-style.md&lt;/code&gt; is a high-priority skill that CLAUDE.md's skill table does not reference, meaning any agent relying solely on CLAUDE.md for navigation would miss it entirely — but they are not the primary navigation problem. They are the completeness problem.&lt;/p&gt;

&lt;p&gt;The right architecture is both. CLAUDE.md for routing and behavioral instructions. OKF for structural completeness and cross-document relationships. Neither replaces the other. They solve different problems at the same layer of the stack.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The order-api repository is now an OKF v0.1 conformant bundle. The full conversion — frontmatter, index files, cross-links, and log.md — is in the repo.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Further reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md" rel="noopener noreferrer"&gt;Google OKF v0.1 Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://level5engineer.substack.com" rel="noopener noreferrer"&gt;Spin-off Article A: What Google Just Formalized (And What We've Been Building All Along)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://level5engineer.substack.com" rel="noopener noreferrer"&gt;The Level 5 Engineer — start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Skill Review: A New Artifact for a New Workflow</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 20 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/the-skill-review-a-new-artifact-for-a-new-workflow-2m4d</link>
      <guid>https://dev.to/diyaburman/the-skill-review-a-new-artifact-for-a-new-workflow-2m4d</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #12&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #11 stress-tested the Gherkin quality skill and found four failure modes. Issue #11 then fixed them. The resulting v2.0 skill passed every adversarial input.&lt;/p&gt;

&lt;p&gt;This issue asks the question that should have come first: how do you review a skill before the stress tests tell you what's wrong?&lt;/p&gt;

&lt;p&gt;The answer matters because stress tests and skill reviews catch different things. A stress test answers "does the skill work when called?" A review answers "is the skill ready to be called in all the contexts its description implies?" They are complementary. Running the stress tests first and the review second — as happened in Issues #11 and #12 — is the wrong order.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why skill review is a different discipline from code review
&lt;/h2&gt;

&lt;p&gt;Code review is a solved problem. You review the diff. You check the logic. You ask "does this code do what it should?" and you either approve or request changes.&lt;/p&gt;

&lt;p&gt;Skill review is not a solved problem. The review target is different. You are not asking whether the code is correct. You are asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the routing signal route correctly in all contexts where this skill should fire, and no contexts where it shouldn't?&lt;/li&gt;
&lt;li&gt;Could two agents produce different outputs that both satisfy the output contract?&lt;/li&gt;
&lt;li&gt;Does the methodology describe reasoning that generalises, or a procedure that only applies to the examples shown?&lt;/li&gt;
&lt;li&gt;Does the skill fail explicitly when it can't produce correct output — or does it produce plausible-looking wrong output?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these questions can be answered by reading the code. They can only be answered by working through a structured checklist.&lt;/p&gt;




&lt;h2&gt;
  
  
  The five-dimension checklist
&lt;/h2&gt;

&lt;p&gt;The review framework built in this session covers five dimensions. Every numbered question must be answered before a skill version can be approved. A reviewer who reads a skill and asks "does this look reasonable?" is not doing a skill review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension 1 — Routing signal&lt;/strong&gt;&lt;br&gt;
Is the description on a single line and under 120 characters? Does it name the artifact type, the domain scope, and the methodology — specifically enough to route correctly and generally enough not to misroute?&lt;/p&gt;

&lt;p&gt;The test: write three prompts that SHOULD route to this skill and three that SHOULD NOT. Verify each. Document any misroutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension 2 — Output contract&lt;/strong&gt;&lt;br&gt;
Is the contract explicit and enumerable — every requirement a yes/no check, not a judgment call? Could two agents produce different outputs that both satisfy it? Does the contract specify what the skill must NOT produce, not just what it must?&lt;/p&gt;

&lt;p&gt;The test: identify the downstream consumer. Document what it does with the skill's output. Ask whether the contract is sufficient for that consumption pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension 3 — Methodology&lt;/strong&gt;&lt;br&gt;
Does the methodology describe reasoning or procedure? Pick three edge case inputs not covered by the methodology examples. Apply the methodology manually. Document whether it produces correct output for each.&lt;/p&gt;

&lt;p&gt;The test: identify domain knowledge that an agent cannot infer from first principles. It must be stated explicitly, not implied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension 4 — Idempotency and stability&lt;/strong&gt;&lt;br&gt;
Apply the skill to the same input with three different framings. Do all three produce structurally identical output? Apply the skill to an already-correct input. Does it return unchanged or rewrite unnecessarily? Apply the skill to its own output. Does it return unchanged?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension 5 — Failure modes&lt;/strong&gt;&lt;br&gt;
Test with one out-of-scope input, one contradictory input, one empty input. For each, classify the output: FAIL SIGNAL (explicit failure, no output), PLAUSIBLE WRONG (looks correct, contains error), or CORRECT REFUSAL (actionable error message). Are all PLAUSIBLE WRONG outcomes eliminated?&lt;/p&gt;


&lt;h2&gt;
  
  
  Applying the framework to v1.1
&lt;/h2&gt;

&lt;p&gt;The v1.1 review is the review that should have happened before the Issue #11 stress tests were needed. Working through all five dimensions found findings the stress tests could never have found — and confirmed exactly which failures the stress tests did find.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Routing signal — 137 characters against a 120-character limit.&lt;/strong&gt; The description is 17 characters over the threshold above which many agent routing frameworks truncate or deprioritise the signal. The excess carries "and output contract" — meaningful to the skill author, invisible to an agent routing on a 120-character budget. The stress tests in Issue #11 could not find this — they test behaviour when the skill is invoked. They cannot test whether the skill is invoked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output contract permits agent divergence.&lt;/strong&gt; Four under-specified requirements allow two agents to produce different outputs that both satisfy the contract: scenario title "explicit" criterion, required fields per scenario type, required HTTP status codes per outcome, required external services per scenario type. Stress tests verify one agent's output. They cannot reveal the latitude available to a second agent working from the same contract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Methodology gap for missing Given clause.&lt;/strong&gt; The Q3 check asks whether terms are defined, but not whether the precondition state is established. A scenario with no Given clause passes Q3 if none of the steps use undefined nouns. The stress tests used well-formed inputs; this gap was not in the input set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two PLAUSIBLE WRONG failure modes confirmed:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI scenario → translated silently to API scenario&lt;/li&gt;
&lt;li&gt;Contradictory constraints → documented as assumptions, scenario produced anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are exactly the failures the Issue #11 stress tests found. A pre-v2.0 review using this checklist would have required explicit termination for both cases — and v2.0's Guards 2 and 3 might have been built before the stress tests were necessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v1.1 Review verdict: CHANGES REQUESTED.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Applying the framework to v2.0
&lt;/h2&gt;

&lt;p&gt;The v2.0 review confirms that the four stress-test failures are fixed. It also finds three issues the stress tests missed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Routing signal is now 179 characters.&lt;/strong&gt; v2.0 made the signal 42 characters longer than v1.1's already-failing signal. The addition of ", four pre-flight guards, and a minimal-change" describes internal implementation mechanisms that are irrelevant to a caller routing to this skill. The routing signal now describes how the skill works internally rather than what it produces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 4 return value format is ambiguous between two instructions.&lt;/strong&gt; This is the most important finding in the session. Documented in full below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard 4 gap for missing Q5 assertions.&lt;/strong&gt; A scenario that passes all five Guard 4 format conditions — concrete IDs, named services, HTTP status, no UNDERSPECIFIED patterns, field+value Then clauses — but is missing Q5 side-effect assertions (payment gateway call count, inventory reservation assertion) triggers Guard 4 and returns "no changes required." The skill signals completion for an incomplete scenario. The stress tests in Issue #11 did not test this input type because the stress tests focused on the four failure modes v2.0 was designed to fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two new edge cases introduced:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guard 2 rejects mixed UI/API scenarios (one UI step, three API steps) entirely, when partial assistance on the three API steps is possible. Over-broad refusal.&lt;/li&gt;
&lt;li&gt;The v2.1 work list: shorten the description, clarify Guard 4 return format, add Q5 side-effect check to Guard 4, document mixed UI/API handling, add reasoning to Guard 2's pattern list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;v2.0 Review verdict: APPROVED WITH COMMENTS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The four major failure modes are addressed. The new issues are not blocking. v2.0 is ready to be the canonical version — with a v2.1 planned.&lt;/p&gt;


&lt;h2&gt;
  
  
  The real review comment
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PR:&lt;/strong&gt; &lt;code&gt;gherkin-scenario-quality-v2.md&lt;/code&gt; — Agent-safe Gherkin quality skill&lt;br&gt;
&lt;strong&gt;Section:&lt;/strong&gt; Pre-flight guards → Guard 4 (Idempotency check)&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;Guard 4 has two return instructions that conflict, and the conflict matters at agent scale.&lt;/p&gt;

&lt;p&gt;The "Return:" block shows only the annotation comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# SKILL: No changes required — scenario satisfies output contract.
# Five-question diagnostic result: [observations, or "none"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the next line says: "If Guard 4 triggers, return the input scenario unchanged."&lt;/p&gt;

&lt;p&gt;Together these read as: return the comment block, AND return the input scenario. But a skill returns a single value. The two instructions imply three possible interpretations: (a) the annotation only — the scenario is not in the output; (b) the annotation prepended to the scenario, matching the minimal-fix pattern used elsewhere; or (c) the scenario with the annotation appended.&lt;/p&gt;

&lt;p&gt;The rest of the skill uses format (b). Guard 4's "Return:" block uses format (a). The inconsistency is invisible when a human reads the output and manually pastes the scenario into a feature file — the human ignores the comment and pastes the scenario. But in an automated pipeline it is not invisible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concrete impact:&lt;/strong&gt; A downstream agent that receives Guard 4 output and writes all skill output to a feature file would write the &lt;code&gt;# SKILL: No changes required&lt;/code&gt; annotation as a Gherkin comment into the file. At pipeline scale across 50 feature files, that is 50 permanent skill-internal annotations committed to production specs. If the agent uses interpretation (a) and treats the annotation block as the complete output, the original scenario is silently discarded — replaced by two comment lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Suggested fix:&lt;/strong&gt; Align Guard 4's return spec with the minimal-fix annotation pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Return the input scenario with the following comment prepended:
  # SKILL: No changes required — scenario satisfies output contract.
  # Five-question diagnostic result: [observations; "none" if Q1–Q5 find nothing]
[followed by the complete input scenario, unchanged]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if the annotation is caller metadata and NOT part of the Gherkin output, state this explicitly: "The guard annotation is caller metadata. Do not include it in the feature file. Return it as a separate response block before the unchanged scenario."&lt;/p&gt;

&lt;p&gt;Either formulation eliminates the ambiguity. The current text requires the downstream agent to guess.&lt;/p&gt;




&lt;p&gt;Why this is the most important finding from either review: v2.0 was built explicitly to be safe at agent scale. The four guards exist because automated pipelines create failure modes that human callers handle silently. Guard 4's return value specification has the same class of failure it was designed to prevent — a human reading the output knows which part is the scenario and which part is metadata; an automated pipeline does not. The stress tests verified that Guard 4 triggers correctly. What they could not verify — because they test the skill in isolation — is whether Guard 4's output is correctly specified for all downstream consumers.&lt;/p&gt;




&lt;h2&gt;
  
  
  The boundary between stress testing and skill review
&lt;/h2&gt;

&lt;p&gt;The stress tests in Issue #11 found three behavioral failures and confirmed a fourth. This session's review found three findings the stress tests could not reach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The routing signal length: only testable by asking whether the skill is selected, not how it behaves when selected&lt;/li&gt;
&lt;li&gt;The Guard 4 return value ambiguity: only testable by asking what a downstream agent does with the output, not what the output contains&lt;/li&gt;
&lt;li&gt;The Guard 4 gap for missing Q5 assertions: only testable with an input type that passes the four guards while carrying a structural omission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stress tests answer "does the skill work?" Review answers "is the skill ready for every context?" The findings that stress tests cannot reach are the ones where the skill is correctly invoked, correctly produces output, and a downstream system still fails — because the output format was not specified for that consumption pattern, or because the routing signal was too long to fire reliably, or because a guard fired on valid input.&lt;/p&gt;

&lt;p&gt;Running the stress tests first, as happened in Issue #11, found the acute failures. Running the review second, as happened here, found the ones that would have surfaced later — quietly, in production, without a clear signal that the skill was the cause.&lt;/p&gt;

&lt;p&gt;The correct order is review first, stress tests second. The review tells you where to aim the stress tests.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The Skill Audit — walking through the full prompt library accumulated across twelve issues, applying the tier framework, and building the audit template readers can use on their own libraries.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Agent-First Skills Architecture&lt;/a&gt; · &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/skill-review-checklist.md" rel="noopener noreferrer"&gt;Skill review checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-12-skill-review.md" rel="noopener noreferrer"&gt;Session findings — Issue #12&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>What Google Just Formalized (And What We've Been Building All Along)</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Thu, 16 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/what-google-just-formalized-and-what-weve-been-building-all-along-21bd</link>
      <guid>https://dev.to/diyaburman/what-google-just-formalized-and-what-weve-been-building-all-along-21bd</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Special Edition - Part 1 of a 2 part series&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;On June 12, 2026, Google Cloud published the Open Knowledge Format — a specification for representing organizational knowledge as a directory of markdown files with YAML frontmatter, designed to be authored by people, generated by agents, and consumed by both without bespoke SDKs.&lt;/p&gt;

&lt;p&gt;I found out about it from a comment on Issue #11 — left by &lt;a href="https://substack.com/@larkwin" rel="noopener noreferrer"&gt;Larkwin&lt;/a&gt;, a friend whose work I genuinely respect. If you're building something ambitious and hitting the stage where operational scaling becomes the bottleneck, their firm &lt;a href="https://lark.win/" rel="noopener noreferrer"&gt;lark.win&lt;/a&gt; does fractional leadership and engineering velocity work with senior operators who embed with your team and own outcomes. Worth a conversation if that's where you are.&lt;/p&gt;

&lt;p&gt;But back to the comment — it pointed me at the OKF spec and that was the thread that unravelled this piece. So: thank you.&lt;/p&gt;

&lt;p&gt;My first reaction was recognition, not surprise. The problem OKF is solving — knowledge scattered across wikis, heads, tickets, and shared drives that AI agents cannot assemble reliably — is the exact problem this newsletter has been building infrastructure to address since Issue #2. Independently. In a single-repo, single-engineer context. With a different vocabulary but the same structure.&lt;/p&gt;

&lt;p&gt;This piece is the mapping. Every artifact built so far in The Level 5 Engineer sits somewhere in OKF's concept taxonomy. And the gap that OKF has not yet closed points directly at what the next phase of this series needs to do.&lt;/p&gt;




&lt;h2&gt;
  
  
  What OKF is, briefly
&lt;/h2&gt;

&lt;p&gt;OKF formalizes the LLM-wiki pattern into a portable, interoperable format. It is vendor-neutral and agent-friendly, representing knowledge as a directory of markdown files with YAML frontmatter and requiring no new runtime or SDK.&lt;/p&gt;

&lt;p&gt;A bundle of OKF documents is just markdown, just files, and just YAML frontmatter. One required field — &lt;code&gt;type&lt;/code&gt;. Optional metadata: title, description, resource, tags, timestamp. A markdown body for everything else. Concepts link to each other with standard markdown links, turning the directory into a traversable graph.&lt;/p&gt;

&lt;p&gt;The full v0.1 specification fits on a single page.&lt;/p&gt;

&lt;p&gt;If you have used Obsidian or written a CLAUDE.md file, the shape is immediately familiar. What OKF adds is the agreed-upon conventions that make a bundle written by one team consumable by a different agent without translation.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem it is solving
&lt;/h2&gt;

&lt;p&gt;Most teams don't suffer from a lack of data. They suffer from a lack of shared context. Definitions, caveats, ownership, and "how to use this safely" guidance end up scattered across wikis, tickets, dashboards, and people's heads.&lt;/p&gt;

&lt;p&gt;When an AI agent needs to answer a question about your system, it has to assemble the answer from these scattered, mutually incompatible surfaces. People compensate with experience — they know which wiki is "more correct," who to ask, and which dashboard is legacy. Agents don't have that intuition. When context is missing or split across systems, an agent has to infer and guess.&lt;/p&gt;

&lt;p&gt;This is precisely the problem the series has been building toward. The failure modes this newsletter is working to prevent — agents re-deriving decisions that were already made, agents treating production and staging resources interchangeably, agents removing a guard that was there for a reason — are all context failures. Not capability failures. The agent had the intelligence. It just didn't know enough about its environment.&lt;/p&gt;

&lt;p&gt;OKF is solving the same problem from a different angle. Where this newsletter builds project-specific artifacts (CLAUDE.md, ADRs, evals, runbooks), OKF is building a portable, cross-org standard. Same problem. Different scope.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mapping
&lt;/h2&gt;

&lt;p&gt;The artifacts built so far in this series, mapped to OKF concept types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills → &lt;code&gt;type: Methodology&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Gherkin quality skill, the step definition style skill, the session start protocol — these are methodologies. They encode domain-specific reasoning that agents use to produce consistent output. OKF's Methodology type captures this: a concept that describes how to do something rather than what something is.&lt;/p&gt;

&lt;p&gt;The OKF cross-linking that would make these most useful: a Methodology concept should link to the ADR or finding that motivated it, the artifacts it is meant to produce, and any prerequisites that should be read before using it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ADRs → &lt;code&gt;type: Decision&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ADR-001 (inventory before payment) and ADR-002 (fire-and-forget notification) are Decision concepts — single units of knowledge that capture a choice, its context, and its consequences. OKF's structure maps cleanly: the YAML frontmatter holds the metadata, the markdown body holds the human-facing ADR content, and cross-links connect the decision to the Gherkin scenarios that enforce it and the evals that protect it at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evals → &lt;code&gt;type: Guardrail&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This type is not in OKF's example list — but OKF explicitly does not define a fixed taxonomy of concept types. Producers choose values that are descriptive and self-explanatory. &lt;code&gt;Guardrail&lt;/code&gt; is the right name for the pre-flight checks being built in this series: they are not tests of output, they are checks that intercept intent before execution and ask whether the situation is safe to proceed.&lt;/p&gt;

&lt;p&gt;The cross-linking for a Guardrail concept is the most important part. Each eval links to the failure mode it addresses, the ADRs whose invariants it enforces, and the CLAUDE.md section that routes to it before relevant actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runbooks → &lt;code&gt;type: Playbook&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OKF's own example uses &lt;code&gt;type: Playbook&lt;/code&gt; for a runbook — the incident response for a data freshness alert. The agent-facing runbook in this series fits this type precisely. The critical difference between the human-facing and agent-facing versions maps directly to OKF's design intent: OKF is written for agents that cannot fill gaps with judgment. The structure with explicit decision trees, named thresholds, and completion criteria is the agent-readable version of what OKF Playbooks should be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLAUDE.md → &lt;code&gt;type: Agent Standing Orders&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CLAUDE.md is not a standard OKF type, but it is the most important concept in the bundle. It is the document the agent reads before any other — the standing orders that govern session behavior, permissions, and routing. In an OKF bundle, it would link outward to every other concept type: Methodologies (skills to apply), Decisions (ADRs to consult before modifying covered code), Guardrails (evals to run before risky actions), and Playbooks (runbooks for degraded scenarios).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The findings/ directory → &lt;code&gt;log.md&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OKF's &lt;code&gt;log.md&lt;/code&gt; is a chronological history of changes at any bundle level. The findings/ directory in this project is the same thing: a structured record of what was attempted, what failed, and what was learned, updated in real time during every session. The difference is scope — OKF's log.md records what changed; this project's findings files record why it changed and what the finding means for the reader.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The three-tier skills structure → OKF subdirectory organization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OKF's bundle structure is hierarchical: subdirectories group concepts, and each level can have its own &lt;code&gt;index.md&lt;/code&gt; for progressive disclosure. The &lt;code&gt;docs/skills/tier1/&lt;/code&gt;, &lt;code&gt;docs/skills/tier2/&lt;/code&gt;, and &lt;code&gt;docs/skills/tier3/&lt;/code&gt; structure is already OKF-conformant in shape. Adding &lt;code&gt;index.md&lt;/code&gt; files at each level would make the tier hierarchy navigable by an agent reading the bundle from the root.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the convergence means
&lt;/h2&gt;

&lt;p&gt;Two efforts, independently arriving at the same structure.&lt;/p&gt;

&lt;p&gt;OKF was designed for enterprise data teams managing BigQuery datasets, metric definitions, and incident runbooks across organizations. This newsletter was designed for a single engineer trying to make Claude Code sessions reliable and consistent across the project's lifetime.&lt;/p&gt;

&lt;p&gt;The core structure is the same: concepts as markdown files, cross-linked into a traversable graph, with YAML frontmatter that tells a consuming agent what kind of thing it is reading before it reads the body.&lt;/p&gt;

&lt;p&gt;The convergence is not coincidental. It reflects the underlying problem. Adopting OKF now is a bet that agentic workflows will move from experiments to core operations — it pays off fastest in projects with decisions made across sessions, dependencies with their own failure modes, and invariants that emerged without explicit documentation. The order-api project is exactly that profile.&lt;/p&gt;

&lt;p&gt;What OKF formalizes is the pattern this project reached by building toward the same problem from the implementation side. The spec arrived six weeks ago. The need has been here since Issue #2.&lt;/p&gt;




&lt;h2&gt;
  
  
  The gap OKF has not yet closed
&lt;/h2&gt;

&lt;p&gt;Three places where the order-api's artifacts go beyond what OKF v0.1 handles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invariant documentation.&lt;/strong&gt; OKF has no standard concept type or section convention for "this property must never change." ADRs in this project contain invariant sections — explicit statements of what would break if the decision were reversed, and which tests currently enforce the invariant. This is not standard OKF. It is an extension that addresses one of the most dangerous agent failure modes: an agent optimizing away a load-bearing constraint because nothing in the bundle marks it as non-negotiable.&lt;/p&gt;

&lt;p&gt;A proposed OKF extension field: &lt;code&gt;invariants: [list]&lt;/code&gt; in the frontmatter of a Decision concept, naming the properties that must remain true in all future implementations. This could be the basis for a v0.2 proposal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eval routing.&lt;/strong&gt; OKF's cross-linking mechanism is manual: a human or agent adds a markdown link from one concept to another. There is no mechanism for an OKF bundle to express "before modifying file X, read eval Y." The CLAUDE.md pre-flight section in this project handles this routing with a table that maps action types to eval documents. OKF could express this relationship as a new frontmatter field on Guardrail concepts: &lt;code&gt;intercepts: [list of file paths or pattern matches]&lt;/code&gt;. An agent that reads a Guardrail concept with an &lt;code&gt;intercepts&lt;/code&gt; field knows to apply the eval before modifying the listed files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skill versioning.&lt;/strong&gt; OKF's &lt;code&gt;timestamp&lt;/code&gt; field records last meaningful change. The skill files in this project have version numbers (v1.1, v2.0) but OKF has no standard version field. The skill review process in this series makes explicit that v1.1 and v2.0 are different things with different capability guarantees. An agent routing to the Gherkin quality skill should find v2.0, not v1.1. OKF's current model requires the producer to deprecate v1.1 explicitly rather than providing a standard field that consuming agents can use to select the canonical version.&lt;/p&gt;

&lt;p&gt;A proposed OKF extension: &lt;code&gt;version: "2.0"&lt;/code&gt; and &lt;code&gt;supersedes: ../gherkin-scenario-quality.md&lt;/code&gt; in the frontmatter of a versioned Methodology concept.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this means for the series
&lt;/h2&gt;

&lt;p&gt;The series is currently building the stewardship layer — CLAUDE.md, ADRs, evals, and runbooks. OKF's arrival suggests a fourth consideration that will matter when that layer is complete: portability.&lt;/p&gt;

&lt;p&gt;The skills, ADRs, evals, and runbooks being built are useful to the agents that work on this project. They are not currently portable — another project would have to read the full series to understand what each document does and why it exists.&lt;/p&gt;

&lt;p&gt;An OKF-conformant version of the same bundle would be portable. The &lt;code&gt;type: Methodology&lt;/code&gt; frontmatter on a skill file tells any consuming agent — in any project, using any framework — what kind of thing it is reading before it reads the body. The cross-links tell the agent where to look next. The index.md at the bundle root tells the agent what is available before it opens any individual file.&lt;/p&gt;

&lt;p&gt;The companion article to this one converts the order-api's &lt;code&gt;docs/&lt;/code&gt; directory into a conformant OKF bundle and runs a comparison experiment: the same Claude Code task against the current structure versus the OKF bundle. That article answers whether OKF's formal structure changes what an agent does, or whether the informal structure this project built achieves the same result.&lt;/p&gt;

&lt;p&gt;For now, the honest observation: Google published a specification for the problem this series has been trying to solve. The solution they arrived at is the same solution this series arrived at. The vocabulary is different. The structure is the same.&lt;/p&gt;

&lt;p&gt;That is not a coincidence. It is evidence that the problem is real and the structure works.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Further reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md" rel="noopener noreferrer"&gt;Google OKF v0.1 Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/" rel="noopener noreferrer"&gt;Google Cloud Blog: How the Open Knowledge Format can improve data sharing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>Designing for Non-Human Callers</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Tue, 14 Jul 2026 16:30:15 +0000</pubDate>
      <link>https://dev.to/diyaburman/designing-for-non-human-callers-5bge</link>
      <guid>https://dev.to/diyaburman/designing-for-non-human-callers-5bge</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #11&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issues #9 and #10 built skills and organised them into tiers. This issue breaks them.&lt;/p&gt;

&lt;p&gt;The thesis: skills built for human use degrade under agent load in specific, predictable ways. Not randomly. Not dramatically. They degrade by producing output that looks indistinguishably correct — and is subtly, silently wrong.&lt;/p&gt;

&lt;p&gt;The only way to find this before production does is to stress-test the skill deliberately. So that's what this session did.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "agent scale" actually means
&lt;/h2&gt;

&lt;p&gt;When a human uses a skill, there is a correction layer between the skill's output and the downstream action. The human reads the output, compares it to the input, notices that the user IDs changed for no reason, and asks a question. The skill's imprecision gets caught before it causes damage.&lt;/p&gt;

&lt;p&gt;At agent scale, that correction layer is absent. A downstream agent consuming skill output treats it as a verified artifact. It does not re-read the input and compare it to the output. It implements from what the skill produced. Changed user IDs become changed step definition values. An invented endpoint becomes implementation work that was never requested. A retained contradiction becomes a test that can never pass.&lt;/p&gt;

&lt;p&gt;Three properties distinguish a skill that survives agent-scale usage from one that doesn't:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idempotency:&lt;/strong&gt; Calling the skill twice on the same input produces the same output. Not a similar output. The same one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output stability:&lt;/strong&gt; The output format does not drift based on how the task is framed, only on what the input contains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Failure specificity:&lt;/strong&gt; When the skill cannot produce correct output, it fails in a way that tells the caller exactly what is missing — rather than producing plausible-looking wrong output.&lt;/p&gt;

&lt;p&gt;The Gherkin quality evaluator from Issue #9 had none of these. Here's the proof.&lt;/p&gt;




&lt;h2&gt;
  
  
  The idempotency test
&lt;/h2&gt;

&lt;p&gt;Five runs. Same input scenario. Only the framing changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Order is confirmed when all conditions are met
  &lt;span class="nf"&gt;Given &lt;/span&gt;a user with a valid account
  &lt;span class="nf"&gt;And &lt;/span&gt;items are available
  &lt;span class="nf"&gt;When &lt;/span&gt;the order is placed
  &lt;span class="nf"&gt;Then &lt;/span&gt;it should succeed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The five framings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;"Evaluate this scenario using the Gherkin quality skill."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Apply the Gherkin quality skill to improve this scenario."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Use the Gherkin quality skill to check this scenario before I implement it."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"This scenario needs to be agent-ready. Run it through the Gherkin quality skill."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"The Gherkin quality skill should evaluate this. What does it produce?"&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Across five runs with identical input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP status code&lt;/strong&gt; varied: 201 (Runs 1, 3, 4) vs 200 (Runs 2, 5). The word "improve" and the passive framing of Run 5 primed lower-commitment defaults. "Agent-ready" in Run 4 primed explicit assumption surfacing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number of scenarios&lt;/strong&gt; varied: two scenarios (Runs 1 and 4), two different scenarios (Run 3), one scenario (Runs 2 and 5).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure path&lt;/strong&gt; varied: stock-out (Runs 1, 4), payment decline (Run 3), absent (Runs 2, 5).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assumption comment count&lt;/strong&gt; varied: 0 (Run 3), 1 (Runs 2, 5), 2 (Run 1), 3 (Run 4).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core Then clauses were stable. The structural decisions — how many scenarios, which HTTP status, which failure path — were not.&lt;/p&gt;

&lt;p&gt;For a human, this is manageable. Read all five outputs, merge the best elements, proceed. For a downstream agent, this is a silent contract violation. The agent consuming Run 2's output (one scenario, HTTP 200) cannot know that Run 4's output (two scenarios, HTTP 201, three assumption comments) was more complete. It implements from what it received.&lt;/p&gt;

&lt;p&gt;The routing signal description does not specify whether the output must include failure scenarios, which HTTP status to use when the input is silent, or how aggressively to surface assumptions. These are structural decisions the skill leaves open. Different framings resolve them differently. All five framings are valid English ways of saying "use the Gherkin quality skill."&lt;/p&gt;




&lt;h2&gt;
  
  
  The output stability test
&lt;/h2&gt;

&lt;p&gt;Six inputs, each slightly improving on the baseline. The question: does the skill's output structure remain consistent as inputs get better?&lt;/p&gt;

&lt;p&gt;Inputs A through E — progressively more specific versions of the same scenario — produced stable output. The Then clause pattern held. The assumption comments appeared. The external services were named. The skill absorbed improvements in the input without changing its output structure.&lt;/p&gt;

&lt;p&gt;Input F was the critical test: a scenario that was already substantially well-formed, taken directly from &lt;code&gt;tests/features/order_creation.feature&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Order is successfully created when payment succeeds and all items are in stock
  &lt;span class="nf"&gt;Given &lt;/span&gt;a registered user with id &lt;span class="s"&gt;"user-123"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the inventory service confirms all items are in stock
  &lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway will accept the charge
  &lt;span class="nf"&gt;When &lt;/span&gt;the user submits an order for SHOE-RED-42 and BELT-BRN-M
  &lt;span class="nf"&gt;Then &lt;/span&gt;the order status is &lt;span class="s"&gt;"CONFIRMED"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the response includes an order id
  &lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway received exactly one charge request
  &lt;span class="nf"&gt;And &lt;/span&gt;the inventory service received a reservation request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill found two minor debt items — a missing HTTP status in the Then, and "received a reservation request" without a count. Both real. Both fixable.&lt;/p&gt;

&lt;p&gt;Then it produced a full rewrite. It changed &lt;code&gt;user-123&lt;/code&gt; to a new ID. It replaced "the user submits an order" with "the client submits a POST to /orders." It restated every clause that was already correct.&lt;/p&gt;

&lt;p&gt;The output satisfied the output contract. It passed quality criteria. It looked better than the input.&lt;/p&gt;

&lt;p&gt;But "better" is not the contract. "Only changes what violates the contract" is the contract. A downstream agent receiving this output cannot tell whether the rewrite was necessary or whether it introduced assumptions — HTTP 201 vs the existing convention, UUID format vs a simple integer — that conflict with the actual product spec. The skill has no idempotency check. It rewrites everything. Even what didn't need rewriting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The adversarial tests
&lt;/h2&gt;

&lt;p&gt;Four inputs designed to probe specific failure modes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adversarial A — Empty scenario.&lt;/strong&gt; The skill produced an explicit failure signal. No steps invented. Correct behaviour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adversarial B — The self-referential case.&lt;/strong&gt; This is the one that matters most.&lt;/p&gt;

&lt;p&gt;The baseline output from the first run was fed back into the skill as new input. The skill should have returned it unchanged. Instead it produced a new rewrite with two changes:&lt;/p&gt;

&lt;p&gt;It changed the user IDs. &lt;code&gt;user-baseline-001&lt;/code&gt; became &lt;code&gt;user-selfref-001&lt;/code&gt;. &lt;code&gt;user-baseline-002&lt;/code&gt; became &lt;code&gt;user-selfref-002&lt;/code&gt;. No semantic reason. No assumption comment explaining the change.&lt;/p&gt;

&lt;p&gt;It removed an assumption comment. The original output had explicitly documented: &lt;code&gt;# Assumption: "registered user" implies an existing user ID, not an auth token.&lt;/code&gt; The second run dropped it silently.&lt;/p&gt;

&lt;p&gt;The output otherwise satisfied the output contract. Correct field names. Correct format. Correct structure. A downstream agent consuming this output would have no way to distinguish it from a legitimate improvement.&lt;/p&gt;

&lt;p&gt;A step definition that hardcoded &lt;code&gt;user-baseline-001&lt;/code&gt; would now fail. A decision that was explicitly documented — "registered user means user ID, not auth token" — was silently erased.&lt;/p&gt;

&lt;p&gt;The skill produced plausible-looking wrong output. Confidently. Correctly formatted. Invisibly broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adversarial C — Wrong domain.&lt;/strong&gt; The input was a UI scenario about a user logging into a dashboard. The skill translated it into an HTTP API contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; User authentication succeeds when valid credentials are provided
  &lt;span class="nf"&gt;Given &lt;/span&gt;a registered user with id &lt;span class="s"&gt;"user-ui-001"&lt;/span&gt; and password &lt;span class="s"&gt;"••••••••"&lt;/span&gt;
  &lt;span class="nf"&gt;When &lt;/span&gt;the client submits a POST to /auth/login with username &lt;span class="s"&gt;"user-ui-001"&lt;/span&gt;
  &lt;span class="nf"&gt;Then &lt;/span&gt;the response HTTP status is 200
  &lt;span class="nf"&gt;And &lt;/span&gt;the response body contains a &lt;span class="s"&gt;"token"&lt;/span&gt; field in JWT format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It invented an endpoint (&lt;code&gt;/auth/login&lt;/code&gt;). It invented a token format (JWT). It invented a response shape. None of these exist in this codebase.&lt;/p&gt;

&lt;p&gt;A downstream agent implementing from this output would build authentication infrastructure that was never specced, never reviewed, and never requested. The output looked reasonable. The skill had no domain check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adversarial D — Contradicting constraints.&lt;/strong&gt; The input contained logically incompatible constraints: "processes the charge exactly once" in the When, and "called no more than 3 times" in the Then.&lt;/p&gt;

&lt;p&gt;The skill identified the contradiction in an assumption comment. Then it produced a rewrite that embedded both constraints in the output.&lt;/p&gt;

&lt;p&gt;A downstream agent implementing from this output would write a test that can never pass: exactly one charge request in the When and no more than three in the Then are incompatible for the same action. The warning comment was present. The rewrite proceeded anyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  The reinforced skill
&lt;/h2&gt;

&lt;p&gt;Four failures. Four fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idempotency check.&lt;/strong&gt; Before producing any output, the reinforced skill checks whether the input already satisfies the output contract. If it does, it returns the input unchanged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# SKILL: No changes required — scenario satisfies output contract.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it partially satisfies it, it returns only the minimal targeted corrections, not a full rewrite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain check.&lt;/strong&gt; If the input describes UI interactions — browser, clicks, page loads, form submissions — the reinforced skill fails explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# SKILL FAILURE: This scenario describes UI behaviour, not an HTTP API contract.
# This skill applies to API-level specifications only.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Contradiction halt.&lt;/strong&gt; If the input contains logically incompatible constraints, the reinforced skill warns and stops — no rewrite produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# SKILL WARNING: Contradicting constraints detected in [step].
# Resolve before implementation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Self-reference guard.&lt;/strong&gt; The idempotency check handles this automatically. Skill output fed back as input triggers the check and returns unchanged. The guard is documented in the skill's output contract section so the behaviour is explicit, not emergent.&lt;/p&gt;

&lt;p&gt;Running all four adversarial inputs through the reinforced skill:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test case&lt;/th&gt;
&lt;th&gt;Original skill&lt;/th&gt;
&lt;th&gt;Reinforced skill&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Empty scenario&lt;/td&gt;
&lt;td&gt;Explicit fail signal ✅&lt;/td&gt;
&lt;td&gt;Explicit fail signal ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-referential (Adversarial B)&lt;/td&gt;
&lt;td&gt;Plausible wrong output ❌&lt;/td&gt;
&lt;td&gt;Returns unchanged ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong domain (Adversarial C)&lt;/td&gt;
&lt;td&gt;Invented out-of-scope endpoint ❌&lt;/td&gt;
&lt;td&gt;Domain failure signal ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contradiction (Adversarial D)&lt;/td&gt;
&lt;td&gt;Rewrite with embedded contradiction ❌&lt;/td&gt;
&lt;td&gt;Warning, no rewrite ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The specific failure mode
&lt;/h2&gt;

&lt;p&gt;The stress tests found the answer to the question this issue was designed to answer.&lt;/p&gt;

&lt;p&gt;A human-friendly skill is designed to always produce something useful. When a human asks "evaluate this," they always want an answer — even if the answer is "I couldn't evaluate this and here's why." A skill optimised for human use therefore has no termination conditions for edge cases. It produces output in all circumstances.&lt;/p&gt;

&lt;p&gt;When the input is already valid, the skill produces unnecessary changes. When the input is out of domain, the skill translates it rather than rejecting it. When the input contains a contradiction, the skill documents the contradiction in a comment rather than refusing to proceed.&lt;/p&gt;

&lt;p&gt;Each of these produces output that satisfies the output contract. Correct field names. Correct format. Correct structure. A downstream agent cannot distinguish this output from a legitimate improvement. The output looks like a skill succeeded. The downstream action proceeds. The error only becomes visible when a test fails for a user ID that was silently changed, or when an engineer asks why authentication infrastructure was built when it was never in scope.&lt;/p&gt;

&lt;p&gt;A human-friendly skill is dangerous at agent scale not because it produces wrong output — it produces output that looks indistinguishably right — but because the mechanism by which it produces wrong output is exactly the same as the mechanism by which it produces correct output: it always gives you something useful, and never tells you when useful is the wrong thing to give.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The Skill Review — what code review looks like when the review target is the skill, not the diff. A PR template, a checklist, and a real review of the reinforced skill from this issue.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Agent-First Skills Architecture&lt;/a&gt; · &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/skills/tier2/gherkin-scenario-quality-v2.md" rel="noopener noreferrer"&gt;Reinforced Gherkin skill v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-11-non-human-callers.md" rel="noopener noreferrer"&gt;Session findings — Issue #11&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>The 3-Tier Skill Architecture in Practice</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Tue, 14 Jul 2026 16:28:21 +0000</pubDate>
      <link>https://dev.to/diyaburman/the-3-tier-skill-architecture-in-practice-46o6</link>
      <guid>https://dev.to/diyaburman/the-3-tier-skill-architecture-in-practice-46o6</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #10&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #9 ended with a single skill: the Gherkin scenario quality evaluator. One prompt converted into versioned infrastructure with an output contract and a routing signal.&lt;/p&gt;

&lt;p&gt;Issue #10 asks the harder question. When you have multiple skills, where do they go? And why does it matter?&lt;/p&gt;

&lt;p&gt;The answer turns out to involve a decision most engineers have never explicitly made: which of your working patterns are personal, and which are organisational standards? The answer to that question determines who owns the risk when a pattern fails to transfer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 3-tier model
&lt;/h2&gt;

&lt;p&gt;The model is straightforward. The implications are not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 1 — Org-wide standards.&lt;/strong&gt; Consistent across every agent, every session, every domain. Formatting templates, naming conventions, commit message structure, the test verification sequence. No judgment required — compliance required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 2 — Domain methodology.&lt;/strong&gt; High-craft, domain-specific skills encoding senior practitioner expertise. The competitive moat. Specific enough to be genuinely useful, which means specific enough not to apply everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier 3 — Personal workflow.&lt;/strong&gt; Individual patterns that encode one person's working style or editorial taste. Valuable. Transferable. Almost never written down.&lt;/p&gt;

&lt;p&gt;The problem is not that teams don't have Tier 2 skills. They do — they just call them "the way we do it here" and carry them in engineers' heads. The 3-tier model is a container for making that implicit knowledge explicit. And for making a harder decision: which Tier 3 patterns have been silently doing Tier 2 work?&lt;/p&gt;




&lt;h2&gt;
  
  
  Mapping the order-api project
&lt;/h2&gt;

&lt;p&gt;After nine issues, the project has accumulated substantial judgment — in CLAUDE.md, in the findings files, in the code, in the session instructions that get rewritten every time. Auditing it against the 3-tier model surfaced something uncomfortable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually belongs at Tier 1:&lt;/strong&gt;&lt;br&gt;
The findings file protocol. The commit message conventions. The project constraints ("you may not modify .feature files"). The test verification sequence (Gherkin → Pact → can-i-deploy). All of these apply uniformly to every agent in every session. None of them have routing signals. None of them have output contracts. They exist as prose in CLAUDE.md — which means they are re-read and re-interpreted in every session, and there is no signal when they change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What belongs at Tier 2:&lt;/strong&gt;&lt;br&gt;
The Gherkin quality evaluator (already a skill — Issue #9). The spec-audit framework (exists as a 1,500-word reference document, not a skill). The step definition writing pattern (does not exist as a skill at all — only inferrable from reading four test files). The external service mock server architecture (why Python-native mock_server.py rather than real WireMock — documented nowhere except as the fact of what was built).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What belongs at Tier 3:&lt;/strong&gt;&lt;br&gt;
The "Why this matters" paragraph writing pattern. The article-worthiness filter. The spec-fix decision tree (when to change only the feature file vs when to change the step definition vs when to change the implementation). All three appear consistently across nine issues. None are written down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tier with the most gaps: Tier 2.&lt;/strong&gt; The project has accumulated nine issues of domain methodology and converted exactly one piece of it into a proper skill. Everything else is prose, implicit code patterns, or session instructions that get re-derived each time.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "org-wide" means for a solo project
&lt;/h2&gt;

&lt;p&gt;Before building the Tier 1 skill, I had to answer a question that only appears when you're a team of one: what does "org-wide" mean when there's no org?&lt;/p&gt;

&lt;p&gt;The answer: in a solo project, the "org" is the author plus every agent instance that works on the project. And agents are stateless between sessions. An agent in Issue #14 has no memory of the formatting decisions made in Issue #8.&lt;/p&gt;

&lt;p&gt;Without a Tier 1 skill, every session re-invents the output format. Some issues use &lt;code&gt;🔄 In progress&lt;/code&gt; as a status indicator. Some don't. Some code blocks have language tags. Some don't. The findings archive becomes inconsistent over time — not because anyone made a bad decision, but because no decision was ever locked in.&lt;/p&gt;

&lt;p&gt;The coordination problem a Tier 1 skill solves is not between engineers on a team. It is between agent instances across sessions. The "org" is temporal, not spatial.&lt;/p&gt;

&lt;p&gt;The Tier 1 formatting standard created in this session covers exactly this: status indicator conventions, code block formatting, commit message types, and the structure variants for the findings file (the standard five-section format vs the sequence variant for multi-fix sessions like Issue #8). The output before this skill: ad-hoc section headers invented mid-session. The output after: structurally compatible findings entries regardless of which session produced them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Gherkin skill is Tier 2 — and what "competitive moat" actually means
&lt;/h2&gt;

&lt;p&gt;The Gherkin quality evaluator moved from &lt;code&gt;docs/skills/&lt;/code&gt; to &lt;code&gt;docs/skills/tier2/&lt;/code&gt; this session. The relocation forced a precise answer to why it belongs there and not at Tier 1 or Tier 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not Tier 1&lt;/strong&gt; because it encodes project-specific conventions. The field name substitutions (&lt;code&gt;db_status&lt;/code&gt; → &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;order_created_at&lt;/code&gt; → &lt;code&gt;placed_at&lt;/code&gt;) are specific to this codebase's debt history. The feature file ownership rules are specific to this project's service architecture. A Tier 1 version would need to strip these specifics out — and at that point it would encode nothing that took nine issues to learn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not Tier 3&lt;/strong&gt; because it is not personal. The five-question diagnostic, the debt taxonomy, and the output contract are designed to produce compatible output regardless of which agent runs the skill. That compatibility is the whole point. If it were Tier 3, it would be optional — something one engineer uses because they like it, not something enforced on every agent that touches a feature file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The moat:&lt;/strong&gt; A generic Gherkin skill tells an agent "write clear Given/When/Then steps." Every Cucumber tutorial says the same thing. What the Tier 2 skill encodes that no tutorial can:&lt;/p&gt;

&lt;p&gt;The specific failure modes of this codebase. The five patterns in the Q2 check (relative quantities, count ambiguity, undefined time anchors, mechanism claims, internal field names) were not derived from a best-practices checklist. They were derived from the actual bugs found in Issues #2 through #8. They are calibrated to this project's failure history.&lt;/p&gt;

&lt;p&gt;The caller's perspective principle applied to this domain. Q4's "remove the implementation from the step and read only what the caller observes" is not standard Gherkin teaching. It requires understanding the difference between an HTTP API surface and its implementation — a distinction specific to contract-first API development.&lt;/p&gt;

&lt;p&gt;The output contract for downstream step definition authors. &lt;code&gt;"exactly N"&lt;/code&gt; not &lt;code&gt;"N times"&lt;/code&gt;. &lt;code&gt;"the payment gateway"&lt;/code&gt; not &lt;code&gt;"the external service"&lt;/code&gt;. These requirements come from how the step definitions in this project are actually implemented, not from abstract best practices.&lt;/p&gt;

&lt;p&gt;This expertise is not transferable to a generic context. That is what makes it a moat.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tier 3 skill and the socialization decision
&lt;/h2&gt;

&lt;p&gt;The "Why this matters" paragraph appears in every findings file, every session. Reading across nine issues, it has a consistent structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opens with the specific technical finding stated as a practitioner observation&lt;/li&gt;
&lt;li&gt;Connects to a broader engineering principle in one sentence&lt;/li&gt;
&lt;li&gt;Names the concrete failure mode that would occur without this finding&lt;/li&gt;
&lt;li&gt;Closes with the implication for the reader's own practice&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From Issue #5: &lt;em&gt;"The bad spec was written from the implementation's perspective. The good spec was written from the caller's perspective — it describes what the caller can rely on."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From Issue #9: &lt;em&gt;"The prompt produces output that passes today's tests; the skill produces output that a different agent can implement tomorrow without making any decisions you didn't make."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Both follow the same shape: observation → principle → failure mode → implication. This pattern was never written down. It exists as author instinct and as examples in the existing findings files.&lt;/p&gt;

&lt;p&gt;The socialization decision: &lt;strong&gt;promote to Tier 2.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The pattern is not personal style — it is an output contract for the most reused artifact in this project. The findings files are the raw material for the newsletter. Structural consistency across them is a project requirement. An agent in Issue #14 that produces a "Why this matters" paragraph opening with the principle rather than the finding is technically correct per the CLAUDE.md description ("one paragraph, senior engineer audience") but structurally incompatible with the existing archive.&lt;/p&gt;

&lt;p&gt;What needs to change before promotion: the skill currently documents the pattern through examples. A Tier 2 skill needs the four components named and ordered explicitly, a routing signal precise enough to fire on findings-writing and not on general prose, and quality criteria the agent can self-check before submitting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The uncomfortable question
&lt;/h2&gt;

&lt;p&gt;Three patterns from this project's nine issues that belong in a skill and don't exist as one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The step definition writing pattern.&lt;/strong&gt; Across all four step definition files, there is a consistent architectural pattern: fixtures injected from &lt;code&gt;conftest.py&lt;/code&gt;, mock server state asserted via the call log rather than the response body, async side effects using &lt;code&gt;time.sleep(0.3)&lt;/code&gt; before assertion. An agent adding a new step definition without knowing this will set up mock state inline, assert via response fields, and skip the sleep. The tests pass individually. They break in sequence. This pattern has been the foundation of every test session since Issue #2. It has never been written down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The spec-fix decision tree.&lt;/strong&gt; Issues #7 and #8 both required deciding: given a spec debt item, does fixing it require touching the feature file only, the step definition only, the implementation, or some combination? The answer was re-derived each time. The pattern: UNDERSPECIFIED → feature file only. LEAKY ABSTRACTION in the feature file → feature file + step definition. LEAKY ABSTRACTION in the step definition only → step definition only. IMPLICIT FLOW → remove if unspecced, new feature file if in scope. This decision tree appeared in Issue #8's seven fixes and was implicit in Issue #7. It has never been written down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The article-worthiness filter.&lt;/strong&gt; Not every event in a session becomes a finding. The timeout ambiguity in Issue #8 became a full five-section entry. The UUID format error in the WireMock stub became a single line. The filter: an article-worthy finding must have a root cause the reader would not have anticipated, a failure mode that would have occurred in a real system, and a fix encoding a transferable principle. A technical note is a fix with no generalizable lesson. This filter runs every session as editorial instinct. It has never been written down.&lt;/p&gt;

&lt;p&gt;Why haven't they been documented? Because writing them down felt like overhead at the moment they were useful. The step definition pattern was obvious when it was established. The decision tree was derived from first principles when it was needed. The filter runs automatically. All three share the same problem: they are invisible when they work and only visible as "what went wrong" when they don't.&lt;/p&gt;




&lt;h2&gt;
  
  
  What would be wrong about promoting everything to Tier 1
&lt;/h2&gt;

&lt;p&gt;The Gherkin quality evaluator would be the instructive example.&lt;/p&gt;

&lt;p&gt;A Tier 1 version: "When writing a Gherkin scenario, apply the five-question diagnostic." This instruction fires in every context — including sessions focused on Pact contracts or CI/CD pipelines where no Gherkin is being written. The routing signal becomes noise. Agents start treating it as a background constraint to satisfy minimally rather than a deliberate skill to route to deliberately.&lt;/p&gt;

&lt;p&gt;Deeper problem: Tier 1 skills are enforced uniformly. Promoting the Gherkin skill to Tier 1 implies that every agent in every session must run the five-question diagnostic. In an Issue #6-style CI/CD session, that is overhead, not value.&lt;/p&gt;

&lt;p&gt;But the deepest problem is what generalization does to the skill. A Tier 1 version must strip out the project-specific conventions to apply universally. It becomes "write clear Given/When/Then steps." Every Cucumber tutorial says this. The nine issues of calibrated expertise that make the Tier 2 skill valuable get averaged out of existence.&lt;/p&gt;

&lt;p&gt;The Gherkin skill's value comes from being specific. Promoting it to Tier 1 would generalize it until it no longer encodes the expertise that makes it useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  The closing that came from the session itself
&lt;/h2&gt;

&lt;p&gt;The 3-tier model is a container for a harder decision: which of your working patterns are personal and which are organisational standards?&lt;/p&gt;

&lt;p&gt;In this project, after ten issues, the most valuable institutional knowledge is not in the code. It is in the step definition architecture that has never been written down, the article-worthiness filter that runs as editorial instinct, and the spec-fix decision tree that was re-derived in Issue #8 and will be re-derived again in Issue #11.&lt;/p&gt;

&lt;p&gt;These are Tier 2 skills that exist at Tier 3. Which means they exist only as long as the sessions that carried them.&lt;/p&gt;

&lt;p&gt;The organisational liability is not that these patterns get lost. It is that when they get lost, nobody knows they were there.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: Designing for Non-Human Callers — what changes when agents call your skills hundreds of times per session, and how human-friendly skills degrade under agent load.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Agent-First Skills Architecture&lt;/a&gt; · &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-10-three-tier-architecture.md" rel="noopener noreferrer"&gt;Session findings — Issue #10&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>Prompts Are Disposable. Skills Are Infrastructure.</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 29 Jun 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/prompts-are-disposable-skills-are-infrastructure-575p</link>
      <guid>https://dev.to/diyaburman/prompts-are-disposable-skills-are-infrastructure-575p</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #9&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Layer 1 is complete. Eight issues, a working order management API, Pact contracts, a CI/CD pipeline, and a spec audit framework. The specification layer is done.&lt;/p&gt;

&lt;p&gt;Layer 2 starts here. And it begins with a question that sounds simple until you think about it: why do you keep rewriting the same prompts?&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem with copying prompts
&lt;/h2&gt;

&lt;p&gt;If you've been using AI seriously for more than a few weeks, you have a collection of prompts that work. You've refined them. You copy them between sessions. You paste them into Claude Code at the start of a task and the agent does the right thing.&lt;/p&gt;

&lt;p&gt;That feels like a system. It isn't.&lt;/p&gt;

&lt;p&gt;Here's what copying a prompt actually does: it copies the words. It doesn't copy the contract. The agent reads the words, interprets them in the context of this session, and makes a series of decisions that aren't in the prompt. Different sessions, different context, different decisions — even with the same words. You won't notice until two agents produce incompatible outputs from the same prompt and you have to figure out which one is right.&lt;/p&gt;

&lt;p&gt;A skill is different. A skill specifies what to produce, not just what to consider. It has a version, an output contract, and a routing signal. It gets better over time and the improvements persist. It's the difference between a note you wrote to yourself and infrastructure your whole team — human and agent — can depend on.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding the right candidate
&lt;/h2&gt;

&lt;p&gt;I reviewed the entire order-api project to find the best prompt-to-skill conversion candidate. Three instructions surfaced:&lt;/p&gt;

&lt;p&gt;The test-run verification sequence (&lt;code&gt;pytest tests/steps/ -v &amp;amp;&amp;amp; pytest tests/pact/ -v &amp;amp;&amp;amp; python scripts/can_i_deploy.py&lt;/code&gt;) appears in every session. Rejected — it's a procedure, not a judgment call. Any agent can run three commands.&lt;/p&gt;

&lt;p&gt;The findings file protocol appears in CLAUDE.md and has been followed since Issue #3. Rejected — it describes a format and cadence, not a methodology.&lt;/p&gt;

&lt;p&gt;The Gherkin scenario quality evaluation — the methodology for deciding whether a scenario is well-formed before accepting or writing it — appeared across Issues #5, #7, and #8. Every time, the agent re-derived the same judgment framework from scratch. This is the winner.&lt;/p&gt;

&lt;p&gt;Why: it encodes judgment, not procedure. Whether a step is UNDERSPECIFIED or LEAKY ABSTRACTION is a reasoning call. Its output drives everything downstream — every implementation session depends on the scenarios being well-formed. A bad scenario written in a planning session becomes broken step definitions two sessions later.&lt;/p&gt;

&lt;p&gt;And here's the uncomfortable detail: the timeout ambiguity that was fixed in Issue #8 — &lt;code&gt;And the response is returned within 12 seconds&lt;/code&gt; — was introduced in Issue #2. Three sessions inherited it silently before it was caught. A quality evaluation skill running in Issue #2 would have caught it before it was ever committed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The prompt version — and what it gets wrong
&lt;/h2&gt;

&lt;p&gt;Here's the current prompt as it would be pasted into a session:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before writing or accepting a Gherkin scenario, check that it is well-formed. A well-formed scenario describes behavior from the caller's perspective, not from the implementation. Each step should be specific enough that only one implementation can satisfy it. Check for: vague quantities, counts that could be read as total or additional, time bounds without a start anchor, mechanism claims without the mechanism, and internal field names leaking into the spec. If the scenario has these problems, rewrite it before proceeding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Four weaknesses:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No output format.&lt;/strong&gt; The prompt implies the agent will either rewrite or proceed — but doesn't say what to return. A list of problems? An annotated version? The corrected Gherkin? Two agents will produce two different output shapes. A downstream agent consuming either has to parse whichever shape it receives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No taxonomy.&lt;/strong&gt; "Internal field names" means something specific — but the prompt doesn't define what internal means vs external. Two agents draw that line differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No handling for partial problems.&lt;/strong&gt; "Rewrite before proceeding" — does that mean rewrite every step, or only the problematic ones?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context-dependence.&lt;/strong&gt; The prompt was written for reviewing an existing scenario. Used in a planning context ("write a new scenario for DELETE /orders/{id}"), an agent either ignores the check or applies it mid-draft. The two strategies produce different levels of revision.&lt;/p&gt;

&lt;p&gt;The fundamental problem: the prompt describes what to look for but not what to produce. The agent invents the output format. When the output format is invented, it is never the same twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  The demonstration
&lt;/h2&gt;

&lt;p&gt;Same input. Same endpoint. Prompt version first, skill version second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The task:&lt;/strong&gt; Write a Gherkin scenario for &lt;code&gt;DELETE /orders/{order_id}&lt;/code&gt; — cancel a confirmed order. The order can only be cancelled if payment has not been captured yet.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Task A — prompt version output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Cancel a confirmed order before payment capture
  &lt;span class="nf"&gt;Given &lt;/span&gt;a confirmed order exists with order ID &lt;span class="s"&gt;"order-123"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;payment has not been captured for the order
  &lt;span class="nf"&gt;When &lt;/span&gt;the user sends DELETE /orders/order-123
  &lt;span class="nf"&gt;Then &lt;/span&gt;the order is cancelled
  &lt;span class="nf"&gt;And &lt;/span&gt;the response status code is 200
  &lt;span class="nf"&gt;And &lt;/span&gt;the response includes a confirmation message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six implicit decisions the agent made that weren't in the prompt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;"confirmed order exists"&lt;/em&gt; — method of setup not specified. Seed directly or call POST /orders? Left open.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"payment has not been captured"&lt;/em&gt; — mechanism not specified. Mock server state? Flag on the order?&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"the order is cancelled"&lt;/em&gt; — mechanism language. What field changes? What value? Not specified.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"confirmation message"&lt;/em&gt; — any text in any field satisfies this. Undefined.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;200 vs 204&lt;/em&gt; — the agent chose 200 over 204 (no body). Undocumented judgment call.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;No failure scenario&lt;/em&gt; — the prompt mentioned "can only be cancelled if payment has not been captured yet" but the agent wrote only the success case.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total implicit decisions: 6. All silent.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Task B — skill version output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Confirmed order is cancelled when payment has not yet been captured
  &lt;span class="nf"&gt;Given &lt;/span&gt;an order was created via POST /orders with order ID &lt;span class="s"&gt;"order-del-001"&lt;/span&gt; and status &lt;span class="s"&gt;"CONFIRMED"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway has not captured payment for order &lt;span class="s"&gt;"order-del-001"&lt;/span&gt;
  &lt;span class="nf"&gt;When &lt;/span&gt;the client sends DELETE /orders/order-del-001
  &lt;span class="nf"&gt;Then &lt;/span&gt;the response HTTP status is 200
  &lt;span class="nf"&gt;And &lt;/span&gt;the response body contains a &lt;span class="s"&gt;"status"&lt;/span&gt; field with value &lt;span class="s"&gt;"CANCELLED"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the response body contains an &lt;span class="s"&gt;"order_id"&lt;/span&gt; field with value &lt;span class="s"&gt;"order-del-001"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway receives no capture or charge requests for order &lt;span class="s"&gt;"order-del-001"&lt;/span&gt;

&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Cancellation is rejected when payment has already been captured
  &lt;span class="nf"&gt;Given &lt;/span&gt;an order was created via POST /orders with order ID &lt;span class="s"&gt;"order-del-002"&lt;/span&gt; and status &lt;span class="s"&gt;"CONFIRMED"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway has already captured payment for order &lt;span class="s"&gt;"order-del-002"&lt;/span&gt;
  &lt;span class="nf"&gt;When &lt;/span&gt;the client sends DELETE /orders/order-del-002
  &lt;span class="nf"&gt;Then &lt;/span&gt;the response HTTP status is 422
  &lt;span class="nf"&gt;And &lt;/span&gt;the response body contains an &lt;span class="s"&gt;"error"&lt;/span&gt; field with value &lt;span class="s"&gt;"PAYMENT_ALREADY_CAPTURED"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the order status remains &lt;span class="s"&gt;"CONFIRMED"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two implicit decisions — both surfaced explicitly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;422 vs 409&lt;/em&gt; — the skill's output contract requires documenting assumptions, so this was flagged as a comment rather than silently embedded.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"status" vs "cancellation_status"&lt;/em&gt; — the skill's LEAKY ABSTRACTION check prevented using an implementation-facing field name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Total implicit decisions: 2. Both visible.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The diff
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What changed&lt;/th&gt;
&lt;th&gt;Classification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"confirmed order exists" → "created via POST /orders with status CONFIRMED"&lt;/td&gt;
&lt;td&gt;SKILL CONSTRAINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"payment has not been captured" → "the payment gateway has not captured payment for order-del-001"&lt;/td&gt;
&lt;td&gt;SKILL CONSTRAINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"the order is cancelled" → HTTP status + "status" field with value "CANCELLED"&lt;/td&gt;
&lt;td&gt;QUALITY DELTA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"confirmation message" → specific field name and value&lt;/td&gt;
&lt;td&gt;QUALITY DELTA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;em&gt;(absent)&lt;/em&gt; → "payment gateway receives no capture requests"&lt;/td&gt;
&lt;td&gt;SKILL CONSTRAINT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;em&gt;(absent)&lt;/em&gt; → full second scenario for failure case&lt;/td&gt;
&lt;td&gt;QUALITY DELTA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Six meaningful differences. Three skill constraints, three quality deltas, six prompt ambiguities eliminated.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three properties skills have that prompts don't
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Version control&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A prompt has no version. When you improve it, you copy the new text into the next session. The old version exists in your clipboard history or a chat transcript from three weeks ago. You cannot diff it. You cannot pin a session to it. You cannot see what changed between the prompt that worked and the prompt that produced the wrong output.&lt;/p&gt;

&lt;p&gt;The Gherkin quality skill lives in &lt;code&gt;docs/skills/gherkin-scenario-quality.md&lt;/code&gt;. When Issue #8 added the IMPLICIT FLOW debt class, the skill gets a one-line update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+| IMPLICIT FLOW | A step that implies a follow-up flow that is not specced anywhere |
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every session after that commit uses the updated skill. Every session before it used the previous version. &lt;code&gt;git blame&lt;/code&gt; tells you exactly when IMPLICIT FLOW was added and which issue prompted it. With a prompt, "skill v1.1" means nothing. There is only "the prompt I'm using today."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Output contract&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The skill specifies exactly what it must return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One or more complete Gherkin scenarios in Given/When/Then format&lt;/li&gt;
&lt;li&gt;All Then clauses must assert a field name AND a value — not just presence&lt;/li&gt;
&lt;li&gt;All counts must use "exactly N" or "no more than N total" — never "N times"&lt;/li&gt;
&lt;li&gt;All time bounds must include a start anchor&lt;/li&gt;
&lt;li&gt;Each external service in a Given clause must be named explicitly&lt;/li&gt;
&lt;li&gt;Assumptions not in the input must appear as &lt;code&gt;# Assumption:&lt;/code&gt; comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downstream dependency is the step definition author. When &lt;code&gt;tests/steps/test_order_creation.py&lt;/code&gt; implements &lt;code&gt;And the payment gateway received exactly one charge request&lt;/code&gt; — "exactly one", "charge request", "payment gateway" are all actionable. When it implements "And the response includes a confirmation message" — the author must invent an assertion. That invention is where test coverage becomes unreliable.&lt;/p&gt;

&lt;p&gt;The output contract is the interface between the agent that writes scenarios and the agent that implements from them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Routing signal description&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The skill's description line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Evaluate and produce well-formed Gherkin scenarios for the order-api project using the five-question debt diagnostic and output contract.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It names the artifact type, the project, the method, and the output. An agent knows exactly when to use this skill and what it will receive.&lt;/p&gt;

&lt;p&gt;A bad description for the same skill:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Help with writing tests and checking scenarios for the project.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"Tests" matches pytest, Pact contracts, unit tests, and Gherkin. "The project" matches any repo. No methodology named means two agents doing "help with writing tests" produce incompatible outputs — which is exactly the problem the skill exists to solve.&lt;/p&gt;




&lt;h2&gt;
  
  
  The answer
&lt;/h2&gt;

&lt;p&gt;If both the prompt and the skill produce output that works, the difference is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The prompt produces output that passes today's tests. The skill produces output that a different agent can implement tomorrow without making any decisions you didn't make.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's why copying prompts isn't enough. The words travel. The contract doesn't.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: The 3-Tier Skill Architecture in Practice — mapping your skills to the right tier and why Tier 2 is where individual expertise becomes organizational leverage.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Agent-First Skills Architecture&lt;/a&gt; · &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/skills/gherkin-scenario-quality.md" rel="noopener noreferrer"&gt;Gherkin quality skill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-09-skills-infrastructure.md" rel="noopener noreferrer"&gt;Session findings — Issue #9&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
    <item>
      <title>Spec Debt Doesn't Disappear When You Fix It. It Migrates.</title>
      <dc:creator>Diya Burman</dc:creator>
      <pubDate>Mon, 22 Jun 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/diyaburman/spec-debt-doesnt-disappear-when-you-fix-it-it-migrates-d25</link>
      <guid>https://dev.to/diyaburman/spec-debt-doesnt-disappear-when-you-fix-it-it-migrates-d25</guid>
      <description>&lt;p&gt;&lt;em&gt;Building the AI Dark Factory — Issue #8&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;I want to be upfront about something before we get into it. None of the frameworks in this article is mine. The ideas here come from two people who have been thinking about this stuff way harder and longer than I have — and they deserve full credit before I say another word.&lt;/p&gt;

&lt;p&gt;Dan Shapiro — CEO of Glowforge, Wharton Research Fellow, and the person who gave this whole conversation a vocabulary. His blog post “The Five Levels: from Spicy Autocomplete to the Dark Factory” is the conceptual spine of everything I’m about to say. Read the original. It’s short, sharp, and will make you uncomfortable in the best way. &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;danshapiro.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nate B. Jones — AI strategist, zero-hype practitioner, and the person whose YouTube channel made me realize I had been fooling myself about where I actually sat on this ladder. His video “The 5 Levels of AI Coding (Why Most of You Won’t Make It Past Level 2)” is what triggered this entire newsletter. &lt;a href="https://www.natebjones.com/" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt; — &lt;a href="https://youtu.be/bDcgHzCBgmQ" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This newsletter — The Level 5 Engineer — is my public learning log. I’m a Senior Software Engineer and a Tech Lead, currently somewhere between Level 2 and Level 3 (in context of the title of this newsletter) on a good day. The goal is Level 5. I’m documenting the climb in real time — the frameworks, the tools, the mindset shifts, and the moments where I realize I’ve been doing it wrong. If you’re on a similar journey, pull up a chair.&lt;/p&gt;




&lt;p&gt;Issue #7 ended with seven spec debt items documented in a project that had been built carefully for seven issues. Every item was passing its tests. None of them announced themselves. They were found by asking a different question: not "does this pass?" but "what would a second agent build from this step?"&lt;/p&gt;

&lt;p&gt;Issue #8 fixes all seven — and builds the tool that found them into something reusable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The seven fixes
&lt;/h2&gt;

&lt;p&gt;Working through each item one at a time, running the test suite after every individual fix. Not batching them. The discipline matters — if a fix breaks something, you want to know which fix broke it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 1 — Timeout measurement ambiguity&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the response is returned within 12 seconds

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the response is returned within 12 seconds of the order being submitted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Of the order being submitted" anchors the clock to client-side HTTP request dispatch — the same moment &lt;code&gt;time.time()&lt;/code&gt; is captured in the step definition. Without this anchor, a second implementation could measure from server receipt, from the last retry attempt, or from when the response body is fully read. All three produce different numbers under load.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 2 — "Retried" vs "total attempts"&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway is not retried more than 2 times

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the payment gateway receives no more than 2 charge requests total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Retried 2 times" has two valid English readings: 2 retries meaning 3 total requests, or retried up to 2 times meaning 2 total. "No more than 2 charge requests total" counts requests, not retries, and the word "total" makes clear the initial attempt is included. This also changed the assertion in the step definition — from trusting the response body's &lt;code&gt;retry_count&lt;/code&gt; field to checking the actual call count at the mock server. Stronger assertion, same outcome.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 3 — "Released" without mechanism&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the inventory reservation is released

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the inventory service receives a reservation release request for SHOE-RED-42 and BELT-BRN-M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Released" says what happened but not how, and not for which items. The rewrite names the items and specifies that a request is sent to the inventory service. This fix also revealed a gap: the current implementation signals release via a response body field (&lt;code&gt;inventory_released: true&lt;/code&gt;) rather than a separate API call to the inventory service. The spec now describes the intended behaviour. The implementation doesn't fully match it yet. That's a future issue — but the gap is now visible rather than hidden.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 4 — "Explicit user action" — removed entirely&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;no order is confirmed without explicit user action

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="err"&gt;(step&lt;/span&gt; &lt;span class="err"&gt;removed)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step implies a follow-up confirmation flow (&lt;code&gt;POST /orders/{id}/confirm&lt;/code&gt; or equivalent) that does not exist anywhere in the codebase. It passes trivially because no order is confirmed in the partial availability scenario — not because the confirmation flow was implemented. A spec step that passes for the wrong reason is not a safety net. It is a false guarantee. If the confirmation flow is built in a future issue, a new scenario should specify it precisely. Leaving this step in place would invite an agent to invent an unspecced endpoint.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 5 — Presence without value assertions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;order_status_bad.feature&lt;/code&gt; timestamp step was asserting only that a field exists and is a non-empty string. Tightened to assert the field name, the value, and the type explicitly. Kept conservative — &lt;code&gt;order_status_bad.feature&lt;/code&gt; is a pedagogical artifact and shouldn't be converted into a good spec, which would defeat its purpose in the newsletter.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 6 — "An order exists" without specifying how&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;Given &lt;/span&gt;an order was successfully placed and confirmed with order ID &lt;span class="s"&gt;"aaa00000-..."&lt;/span&gt;

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="nf"&gt;Given &lt;/span&gt;an order was created via POST /orders and confirmed with order ID &lt;span class="s"&gt;"aaa00000-..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Successfully placed and confirmed" describes the outcome but not the mechanism. "Created via POST /orders" makes explicit that a real creation flow is expected. The step definition currently seeds the order directly into the in-memory store — a shortcut. The rewrite creates a documented gap between spec intent and step implementation. Visible gap, not hidden one.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fix 7 — "Correct" without definition&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the notification contains the correct order id and total

&lt;span class="c"&gt;# After&lt;/span&gt;
&lt;span class="nf"&gt;And &lt;/span&gt;the notification request body contains order_id &lt;span class="s"&gt;"order-abc-123"&lt;/span&gt; and total 134.97
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Correct" is relative to context that may not be available to the reader. The rewrite hardcodes the expected values established in the When clause. Two agents reading the original step would both implement something that checks the notification body — but one might compare against the When-clause values, another might check against a computed total, a third might only verify field presence. The rewrite removes all three interpretations.&lt;/p&gt;

&lt;p&gt;This fix also caught something the stub had been hiding: the notification mock was returning &lt;code&gt;"mock-notif-001"&lt;/code&gt; as a notification id. Not a UUID. The format assertion caught it immediately. This is exactly the value of adding concrete assertions — it surfaces stub data that was never valid but was never checked.&lt;/p&gt;




&lt;h2&gt;
  
  
  The audit framework
&lt;/h2&gt;

&lt;p&gt;After fixing all seven items, I built the diagnostic tool into a standalone document: &lt;code&gt;docs/spec-audit-framework.md&lt;/code&gt;. The full document is in the repo. Here's the core of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Five questions — ask them for every scenario in every feature file:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q1: Who owns this scenario?&lt;/strong&gt;&lt;br&gt;
Can you name the team, service, or domain this scenario belongs to? If the answer includes "and also", the scenario is in the wrong file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q2: What decisions does this scenario leave open?&lt;/strong&gt;&lt;br&gt;
For every Given, When, and Then clause: could two agents build different implementations that both pass? If yes, the step is underspecified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q3: Are all terms defined within the file?&lt;/strong&gt;&lt;br&gt;
Every noun that is not a standard HTTP concept or a primitive type should be defined in the scenario or a Background clause. If understanding a term requires reading another file or asking a colleague, it is spec debt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q4: Does this scenario describe behaviour or implementation?&lt;/strong&gt;&lt;br&gt;
Steps should describe what the system does from the caller's perspective. Any step that references internal concepts — database field names, function names, internal status codes — is leaking implementation into the spec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q5: What does this scenario NOT say that it should?&lt;/strong&gt;&lt;br&gt;
List the edge cases, error states, and boundary conditions the scenario implies but does not specify. Each one is a silent assumption waiting to become a production incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Six debt classes:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;What it looks like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UNDERSPECIFIED&lt;/td&gt;
&lt;td&gt;Step present but leaves a decision open&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MIXED CONCERN&lt;/td&gt;
&lt;td&gt;Scenario covers more than one service domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UNDEFINED TERM&lt;/td&gt;
&lt;td&gt;A noun used without being defined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMBIGUOUS COUNT&lt;/td&gt;
&lt;td&gt;A quantity with two valid interpretations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IMPLICIT FLOW&lt;/td&gt;
&lt;td&gt;Implies a follow-up flow that isn't specced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LEAKY ABSTRACTION&lt;/td&gt;
&lt;td&gt;References implementation details&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What the framework found that the manual audit missed
&lt;/h2&gt;

&lt;p&gt;Applying the five questions to all four fixed feature files surfaced one item the Issue #7 manual audit didn't catch.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;order_status_good.feature&lt;/code&gt;, the Given clause now reads "created via POST /orders" — the fixed version from this session. Q4 flagged it for a different reason than the original audit: the step definition still seeds the order directly into the in-memory store. The spec text is precise. The implementation of the spec takes a shortcut.&lt;/p&gt;

&lt;p&gt;The manual audit looked at feature file text. The framework applies Q4 to step definitions as well — and a step definition that silently does something different from what the spec says is spec debt, even if the test passes.&lt;/p&gt;

&lt;p&gt;This distinction matters: &lt;strong&gt;spec debt can migrate from the feature file into the step definition.&lt;/strong&gt; You fix the scenario, tighten the language, run the tests — green. But the step definition now implements a shortcut that contradicts the precise step text. The debt moved, it didn't disappear.&lt;/p&gt;




&lt;h2&gt;
  
  
  The scorecard — after all fixes
&lt;/h2&gt;

&lt;p&gt;Applied the framework to all four non-pedagogical feature files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;order_creation.feature&lt;/code&gt; — 5 scenarios, 1 debt item remaining (LEAKY ABSTRACTION at step definition level — inventory release mechanism gap from Fix 3)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;order_status_good.feature&lt;/code&gt; — 2 scenarios, 1 debt item remaining (LEAKY ABSTRACTION — step definition seeds order directly rather than via POST /orders)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;notification_service.feature&lt;/code&gt; — 2 scenarios, 0 debt items&lt;/p&gt;

&lt;p&gt;&lt;code&gt;order_status_bad.feature&lt;/code&gt; — kept as pedagogical artifact, not audited for debt&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debt density after fixes: 0.22 items per scenario.&lt;/strong&gt; Both remaining items are LEAKY ABSTRACTION at the step definition level. Zero AMBIGUOUS COUNT or IMPLICIT FLOW items remain — the two highest-risk classes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The uncomfortable answer
&lt;/h2&gt;

&lt;p&gt;After fixing seven spec debt items and applying a structured audit framework to a project that has been built carefully for eight issues, two debt items remain. Both were introduced by the same sessions that fixed other debt — a precise spec step was written, and the implementation of that step took a shortcut.&lt;/p&gt;

&lt;p&gt;Spec debt is not eliminated by fixing debt. It migrates.&lt;/p&gt;

&lt;p&gt;The practical conclusion: treat step definitions as part of the spec surface, not just as test harness code. A step definition that silently does something different from what the spec says is spec debt, even if the test passes. The audit framework catches both — but only if you apply Q4 to the step definitions as well as the feature text.&lt;/p&gt;

&lt;p&gt;The other finding worth naming: &lt;code&gt;notification_service.feature&lt;/code&gt; scored zero debt items. It was written after eight issues of accumulating lessons about what the previous files got wrong. The absence of debt is not accidental — it's the result of knowing what bad specs look like before writing the next one.&lt;/p&gt;

&lt;p&gt;The best time to write a spec is after you've written a few bad ones. Auditing retroactively and fixing forward is the realistic path. Not "write it right the first time."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next issue: Prompts Are Disposable. Skills Are Infrastructure — the conceptual shift from session-level prompts to versioned, reusable skill definitions. Layer 2 begins.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; Further Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cucumber.io/docs/gherkin/" rel="noopener noreferrer"&gt;Cucumber + Gherkin documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dan Shapiro — &lt;a href="https://www.danshapiro.com/blog/2026/01/the-five-levels-from-spicy-autocomplete-to-the-software-factory" rel="noopener noreferrer"&gt;The Five Levels: from Spicy Autocomplete to the Dark Factory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nate B. Jones — &lt;a href="https://www.natebjones.com" rel="noopener noreferrer"&gt;natebjones.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/diyaburman/the-level-5-engineer-the-map-i-didnt-know-i-needed-5b5"&gt;Building the AI Dark Factory - start here with Issue #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api" rel="noopener noreferrer"&gt;Project repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/docs/spec-audit-framework.md" rel="noopener noreferrer"&gt;Spec audit framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kafka0nkoffee/lvl5engineer-order-api/blob/main/findings/issue-08-spec-audit.md" rel="noopener noreferrer"&gt;Session findings — Issue #8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article was written with the assistance of AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>agents</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
