<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[bz's Substack]]></title><description><![CDATA[bz's Substack]]></description><link>https://bfzhao.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!Co-B!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7afb76c-2559-469a-88c3-bb38f7800895_144x144.png</url><title>bz&apos;s Substack</title><link>https://bfzhao.substack.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 17 Jul 2026 12:20:17 GMT</lastBuildDate><atom:link href="https://bfzhao.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[bz]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[bfzhao@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[bfzhao@substack.com]]></itunes:email><itunes:name><![CDATA[bz]]></itunes:name></itunes:owner><itunes:author><![CDATA[bz]]></itunes:author><googleplay:owner><![CDATA[bfzhao@substack.com]]></googleplay:owner><googleplay:email><![CDATA[bfzhao@substack.com]]></googleplay:email><googleplay:author><![CDATA[bz]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Beyond Vibe Coding: Rebuilding the Broken Chain of Trust with Semantic Contracts]]></title><description><![CDATA[AI writes code faster than humans can review it. It's time to shift from manual code inspection to semantic inspection.]]></description><link>https://bfzhao.substack.com/p/beyond-vibe-coding-rebuilding-the</link><guid isPermaLink="false">https://bfzhao.substack.com/p/beyond-vibe-coding-rebuilding-the</guid><dc:creator><![CDATA[bz]]></dc:creator><pubDate>Fri, 17 Jul 2026 03:56:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Co-B!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7afb76c-2559-469a-88c3-bb38f7800895_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://bfzhao.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://bfzhao.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>&#128161; <strong>TL;DR Notice </strong>AI writes code faster than humans can review it, creating a massive trust crisis. Unit tests and prompt engineering aren't enough. Here propose <strong>Semantic Contracts</strong>&#8212;a type-safe, compile-time blueprint that sits between your requirements/prpmpts and code, guaranteeing correctness no matter who (or what) wrote the implementation.</p><div><hr></div><p>AI-driven development (often called &#8220;Vibe Coding&#8221;) has massively boosted our coding speed. However, because we don&#8217;t truly know how AI models make their decisions, we are facing a fundamental crisis of trust.</p><p>This paper proposes a practical solution: <strong>Semantic Contracts</strong>.</p><p>A semantic contract is a structured, verifiable blueprint of your core business logic. Positioned right between raw human requirements and actual code, it uses typed states, simple building blocks (combinators), and compile-time checks to guarantee that any implementation&#8212;whether written by a human or generated by an AI&#8212;is automatically trustworthy as long as it fits the contract.</p><p>In this blog, I describe what semantic contracts are, explain their math-like building blocks, demonstrate them using sorting algorithms and e-commerce checkout examples, and discuss how they can plug into your existing systems.</p><h2>1. The Problem: How AI Broke the Software Engineering &#8220;Chain of Trust&#8221;</h2><p>In the pre-AI era, software engineering relied on a highly structured pipeline to build trust:</p><p><strong>Requirements &#8594; Architecture &#8594; Detailed Design &#8594; Coding &#8594; Testing &#8594; Code Review &#8594; Deployment</strong></p><p>Every step had clear inputs, outputs, and human ownership. We trusted the software because we trusted the <em>process</em>. Even if we couldn&#8217;t mathematically prove the code was 100% bug-free, we had confidence because it went through multiple rounds of human review and automated testing.</p><p>In the AI era, this entire pipeline has collapsed. With &#8220;Vibe Coding,&#8221; you type a prompt, and the AI immediately spits out running code. The middle steps are gone. While we try to catch up with techniques like prompt engineering or automated test harnesses, the path from a user&#8217;s prompt to the final code remains a black box. Relying purely on AI self-correction or quick human reviews is, frankly, wishful thinking.</p><p>This shift has broken our chain of trust in four ways:</p><ul><li><p><strong>Unknown AI Behavior:</strong> AI code comes from neural networks with hundreds of billions of parameters. We cannot fully predict or understand it. The exact same prompt can yield completely different code under the hood.</p></li><li><p><strong>Untraceable Bugs:</strong> When AI code fails, it&#8217;s incredibly hard to trace the failure back to a specific design flaw or logical error.</p></li><li><p><strong>Unpredictable Fixes:</strong> Prompting an AI to fix one bug can easily introduce unexpected side effects elsewhere.</p></li><li><p><strong>Impossible Code Reviews:</strong> Humans simply cannot review code as fast as AI can write it. Reviews quickly become a checkbox exercise.</p></li></ul><p>If we cannot solve the question of <strong>&#8220;how to trust AI-generated code,&#8221;</strong> the massive speedups from AI will always come with risks we cannot afford to take.</p><h2>2. The Solution: A Verifiable Bridge Between Ideas and Code</h2><p>To fix this, we need a new layer in our workflow. It must be:</p><ol><li><p><strong>Between Requirements and Code:</strong> More precise than vague human language, but more abstract than actual code.</p></li><li><p><strong>Guaranteed to Work:</strong> Any code that matches this layer must behave exactly as intended.</p></li><li><p><strong>Composable:</strong> You can snap smaller pieces together to build larger systems.</p></li><li><p><strong>Checked at Compile-Time:</strong> Errors should be caught by the compiler, not during runtime.</p></li></ol><p>I call this <strong>Semantic Contracts</strong>.</p><p>While semantic contracts are not exclusive to AI, they are highly effective at preventing AI &#8220;hallucinations&#8221; because they strip away irrelevant details and enforce strict types. If an AI generates a bad implementation, the compiler will simply refuse to build it.</p><blockquote><p>&#128161; <strong>A simple analogy:</strong></p><p>Imagine the classic joke of putting an elephant in a fridge in three steps:</p><ol><li><p>Open the fridge.</p></li><li><p>Put the elephant in.</p></li><li><p>Close the fridge.</p></li></ol><p>A semantic contract guarantees that these three steps happen <em>exactly in this order</em>. It secures the <strong>process</strong>, even though it doesn&#8217;t verify if the elephant actually fits inside.</p></blockquote><h2>3. Why Existing &#8220;Formal Methods&#8221; Failed</h2><p>Computer scientists have tried to prove program correctness for decades (using tools like Hoare Logic, Z language, or Model Checking). Yet, they never went mainstream because:</p><ul><li><p><strong>They focus on &#8220;finding bugs&#8221; rather than &#8220;building things right.&#8221;</strong> Traditional methods try to verify code <em>after</em> it is written. That is passive and incredibly hard. We want to make correctness a natural byproduct of <em>how we build</em> the code in the first place.</p></li><li><p><strong>Writing specifications is too hard.</strong> Writing perfect mathematical rules for a complex business system is often harder and more exhausting than writing the actual code.</p></li><li><p><strong>The State Explosion Problem.</strong> Verifying large programs requires checking astronomical numbers of possible pathways, which quickly crashes even the best verification tools.</p></li></ul><p>Our approach does not try to &#8220;prove everything.&#8221; Instead, it focuses on <strong>process guarantees</strong>. By using structured building blocks, your code becomes correct by design, not by coincidence.</p><h2>4. What is a Semantic Contract?</h2><h3>4.1 The Blueprint</h3><p>A semantic contract is a structured, verifiable description of a business operation. It consists of three parts:</p><p><span>Rust</span></p><pre><code><code>contract Name(input_state) : output_state
= structural_definition
with Capability { ... }</code></code></pre><ul><li><p><code>contract Name(input_state) : output_state</code> (The Signature): Defines what state goes in, and what possible states can come out.</p></li><li><p><code>= structural_definition</code> (The Skeleton): An expression tree made of basic building blocks (combinators).</p></li><li><p><code>with Capability</code> (The Extra Powers): Attaches behaviors like database transactions, retries, rate-limiting, or logging.</p></li></ul><p>Once defined, any contract can easily be reused inside other contracts.</p><h3>4.2 &#8220;States&#8221; are the Only Results</h3><p>Instead of throwing random errors, our contracts return explicit &#8220;States.&#8221; A state is a simple data structure that carries information:</p><pre><code><code>Success(TransactionId) |
InsufficientBalance(available: Money) |
Processing(Token) |
Blocked</code></code></pre><p>If your business rules are violated (e.g., trying to transfer negative money), you don&#8217;t throw an exception. You simply return an <code>InvalidAmount</code> state.</p><p><strong>Handling &#8220;Uncaught&#8221; States (Exceptions):</strong></p><p>By default, contracts have two basic states: <code>Success</code> and <code>Fail</code>. If a contract returns a custom state (like <code>InsufficientBalance</code>) and the next step doesn&#8217;t explicitly handle it, the compiler treats this as an &#8220;unhandled exception.&#8221; It will then:</p><ol><li><p><strong>Pass it up</strong> if the parent contract can handle it.</p></li><li><p><strong>Throw a compile-time error</strong> if nobody handles it. This forces developers (or AI) to handle every edge case before the code can even run.</p></li></ol><h3>4.3 The Building Blocks (Combinators)</h3><p>We use a small set of predefined operations to chain business logic together:</p><ul><li><p><code>Seq&lt;A, B&gt;</code><strong><span>: </span></strong><span>Run A, then B. If A fails, stop and return the failure.</span></p></li><li><p><code>Par&lt;A, B&gt;</code><strong><span>:</span></strong><span> Run A and B at the same time. Both must succeed.</span></p></li><li><p><code>Batch&lt;A&gt;</code><strong><span>:</span></strong><span> Run operation A on a list of items, one by one.</span></p></li><li><p><code>Race&lt;A, B&gt;</code><strong><span>:</span></strong><span> Run A and B. Return whoever finishes first.</span></p></li><li><p><code>ScatterGather&lt;S, G&gt;</code><strong><span>:</span></strong><span> Split a task, run in parallel, and merge results.</span></p></li><li><p><code>Transaction&lt;A, B&gt;</code><strong><span>:</span></strong><span> If step B fails, roll back step A.</span></p></li><li><p><code>Timed(duration, A)</code><strong><span>:</span></strong><span> A must finish within the limit, or it fails.</span></p></li></ul><p>This maybe not a complete list to support all common cases, but they are powerful enough to represent most any business workflow. As they have predictable math-like rules, the compiler can easily check if your pipeline makes sense.</p><h2>5. Example 1: A Sorting Algorithm</h2><p>Let&#8217;s see how a standard sorting algorithm looks as a semantic contract.</p><h3>5.1 Defining the Contract</h3><p>First, we define our &#8220;trusted foundation tools&#8221; (atomic operations):</p><pre><code><code>contract CheckSorted&lt;T&gt;(List&lt;T&gt;) :
    Sorted(List&lt;T&gt;) |
    Unknown(List&lt;T&gt;)
= Trusted_Atomic_Operation

contract Partition&lt;T&gt;(List&lt;T&gt;) :
    Success(Less: List&lt;T&gt;, Greater: List&lt;T&gt;) |
    Failed(Error)
= Trusted_Atomic_Operation

contract Merge&lt;T&gt;(List&lt;T&gt;, List&lt;T&gt;) :
    Success(Sorted: List&lt;T&gt;) |
    Failed(Error)
= Trusted_Atomic_Operation
</code></code></pre><p>Now, we define the actual sorting process:</p><pre><code><code>contract Sort&lt;T&gt;(List&lt;T&gt;) :
    Success(Sorted: List&lt;T&gt;) |
    Failed(Error)
= Seq&lt;
    CheckSorted {
        Sorted(list) -&gt; Success(list),
        Unknown(list) -&gt; Seq&lt;
            Success(less, greater) = Partition(list),
            {sorted_less, sorted_greater} = Par&lt;Sort(less), Sort(greater)&gt;,
            Merge(sorted_less, sorted_greater)
        &gt;
    }
&gt;</code></code></pre><h3>5.2 Why This is Guaranteed to Work</h3><p>The structure of the contract makes it impossible to fail:</p><ol><li><p><strong>Check:</strong> If the list is already sorted, return it immediately (this handles empty or single-item lists, stopping the recursion).</p></li><li><p><strong>Divide:</strong> Split the list into &#8220;less than&#8221; and &#8220;greater than&#8221; piles.</p></li><li><p><strong>Sort:</strong> Run sorting on both halves in parallel.</p></li><li><p><strong>Merge:</strong> Combine the results.</p></li></ol><p>This contract assumes the atomic tools (<code>Partition</code> and <code>Merge</code>) work correctly. How we guarantee <em>those</em> works is a separate issue (via unit tests or formal proof), but the overall <em>assembly</em> of our sorting algorithm is 100% verified by the compiler.</p><p>Note how for a pure math problem like sorting, the contract is essentially the algorithm itself. For business applications, however, contracts behave differently.</p><h2>6. Example 2: E-Commerce Checkout</h2><p>Let&#8217;s design a real-world checkout system where we need to charge a user and deduct inventory.</p><pre><code><code>contract PlaceOrder(AccountId, List&lt;ItemId&gt;) :
    Success |
    Failed(Error)
= Seq&lt;Payment, Inventory&gt;</code></code></pre><h3>6.1 Adding Edge Cases (Refining the States)</h3><p>Payments can fail due to low balances; items can be out of stock. Let&#8217;s make these outcomes explicit:</p><pre><code><code>contract Payment(AccountId, Money, OrderId) :
    Success(TransactionId) |
    InsufficientBalance(available: Money) |
    Failed(Error)

contract Inventory(OrderId, List&lt;ItemId&gt;) :
    Success(List&lt;ReservationId&gt;) |
    InsufficientStock(item: ItemId, available: Quantity) |
    Failed(Error)
</code></code></pre><p>Now, we update our main <code>PlaceOrder</code> contract. The compiler will force us to include these new potential failure states in the main output:</p><p><span>Rust</span></p><pre><code><code>contract PlaceOrder(AccountId, List&lt;ItemId&gt;) :
    Success |
    InsufficientBalance(available: Money) |   // From Payment
    InsufficientStock(item: ItemId, available: Quantity) |  // From Inventory
    Failed(Error)
= Transaction&lt;Seq&lt;Payment, Inventory&gt;&gt;
</code></code></pre><h3>6.2 Zooming In</h3><p>Let&#8217;s define the steps inside <code>Payment</code> and <code>Inventory</code>:</p><pre><code><code>contract Payment(AccountId, Money, OrderId) :
    Success |
    InsufficientBalance(available: Money) |
    Failed(Error)
= Seq&lt;
    CheckAccount {
        Exists(account): CheckBalance {
            Sufficient: DeductBalance,
            Insufficient(available): InsufficientBalance(available)
        }
        NotFound: Failed("Account not found")
    }
&gt;

contract Inventory(OrderId, List&lt;ItemId&gt;) :
    Success(List&lt;ReservationId&gt;) |
    InsufficientStock(item: ItemId, available: Quantity) |
    Failed(Error)
= Batch&lt;ReserveInventory&gt;
</code></code></pre><h3>6.3 Adding New Features</h3><p>What if we want to send an email notification after a checkout attempt, regardless of whether it succeeded or failed? We can update the parent contract like this:</p><pre><code><code>contract PlaceOrder(AccountId, List&lt;ItemId&gt;, Email) :
    Success |
    InsufficientBalance(available: Money) |
    InsufficientStock(item: ItemId, available: Quantity) |
    Failed(Error)
= Transaction&lt;Payment, Inventory&gt; {
     _: SendNotification
  }</code></code></pre><p>This showcases the natural engineering process: starting with a high-level concept and gradually adding detail. Traditional design documents try to do this but lack compiler validation; code has the compiler but hides the big-picture design. Semantic contracts bridge this gap perfectly.</p><h2>7. Elevating Logic to Types</h2><p>The core idea here is to <strong>treat business logic as a type system</strong>.</p><p>In traditional programming, business rules are buried inside nested <code>if/else</code> statements, database calls, and error-catching blocks. There is no automated way to prove that they all play nice together.</p><p>Semantic contracts turn &#8220;payment&#8221; into a set of strict, typed rules. When everything is typed:</p><ul><li><p><strong>You can plug things together:</strong> <code>Payment</code> can be safely used in any larger checkout system.</p></li><li><p><strong>You can verify it instantly:</strong> The compiler checks if your logic matches your blueprint.</p></li><li><p><strong>You can swap implementations:</strong> Any code that satisfies the <code>Payment</code> contract can be swapped in without breaking the system.</p></li></ul><p>It replaces messy, ad-hoc <code>if/else</code> spaghetti with compile-time guarantees.</p><h2>8. Plugs and Play: Integrating with Existing Systems</h2><p>Most existing codebases do not have semantic contracts. How do we adopt this?</p><p>Here we define a <strong>Hierarchy of Trust</strong>:</p><ol><li><p><strong>Infrastructure Trust:</strong> Low-level components like the Linux Kernel, TCP/IP, or PostgreSQL. We assume these work correctly because they are battle-tested by millions of developers.</p></li><li><p><strong>Platform Trust:</strong> Your programming language&#8217;s standard library and runtime.</p></li><li><p><strong>Contract Trust:</strong> The safety net maintained by our Semantic Contract compiler.</p></li><li><p><strong>Untrusted Code:</strong> Raw AI prompts, messy legacy code, or unverified scripts.</p></li></ol><p>Our compiler doesn&#8217;t try to prove that the Linux kernel is correct. It builds on top of &#8220;Infrastructure&#8221; and &#8220;Platform&#8221; trust, and focuses entirely on proving that your custom business logic (the Contract layer) is put together correctly.</p><h2>9. Humans and AI: Working Together</h2><p>Traditionally, we trust human code because we can hold humans accountable. We don&#8217;t trust AI code because neural networks are unpredictable, and humans can&#8217;t keep up with reviewing them.</p><p>With semantic contracts, <strong>it doesn&#8217;t matter who wrote the code</strong>.</p><p>Both human-written and AI-generated code must obey the exact same contract. Because contracts are highly restrictive, translating a contract into running code is straightforward. In fact, AI excels at this type of constrained translation. If the AI makes a mistake, the contract compiler immediately catches it.</p><p>Furthermore, AI is great at writing the contracts themselves. Because contracts are abstract and highly structured, they prevent the AI from &#8220;hallucinating&#8221; details or getting distracted by irrelevant context.</p><ul><li><p><strong>The human&#8217;s role:</strong> Review or design high-level semantic contracts, and build verified, bulletproof atomic tools.</p></li><li><p><strong>The AI&#8217;s role:</strong> Generate the code that implements those contracts, and flesh out the boilerplate.</p></li></ul><h2>10. Conclusion</h2><p>The core takeaway is simple: <strong>We shouldn&#8217;t care </strong><em><strong>where</strong></em><strong> code comes from; we should only care whether the codes obeys the construction semantic. </strong></p><p>With semantic contracts:</p><ul><li><p>Code must meet strict mathematical and structural rules to compile.</p></li><li><p>We don&#8217;t need to choose between AI development speed and software safety. AI can generate code at lightning speed, and our compiler will act as an automated quality gate.</p></li><li><p>Humans can focus on designing high-level logic rather than reviewing endless lines of code.</p></li></ul><p>By using semantic contracts as a bridge between ideas and code, we can finally build a software development process that is fast, automated, and&#8212;above all&#8212;fully trustworthy.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://bfzhao.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading bz's Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item></channel></rss>