<?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: Vasiliy Shilov</title>
    <description>The latest articles on DEV Community by Vasiliy Shilov (@uxter).</description>
    <link>https://dev.to/uxter</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3800482%2F7fb0fd1b-d5a3-4a45-8c98-708f61d9b58b.jpeg</url>
      <title>DEV Community: Vasiliy Shilov</title>
      <link>https://dev.to/uxter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uxter"/>
    <language>en</language>
    <item>
      <title>Code Is Not the Source of Truth. It's a Materialized View.</title>
      <dc:creator>Vasiliy Shilov</dc:creator>
      <pubDate>Wed, 18 Mar 2026 23:46:27 +0000</pubDate>
      <link>https://dev.to/uxter/code-is-not-the-source-of-truth-its-a-materialized-view-3hag</link>
      <guid>https://dev.to/uxter/code-is-not-the-source-of-truth-its-a-materialized-view-3hag</guid>
      <description>&lt;p&gt;A short piece about what happens to development when code stops being the center. More of a reflection: how we think, what we fix in place, and why speed is no longer the main constraint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Introduction&lt;/strong&gt; What this is about and why it matters now. The shift from "write faster" to "understand more clearly".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Is Not the Center&lt;/strong&gt; Code as cache and as a projection of decisions. Source of truth is not files but invariants and intent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intent and Invariants&lt;/strong&gt; What to fix before code and why. Decision first, then code - not the other way around.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two Modes&lt;/strong&gt; Flow and serialization: when something new is born, when clarity appears. How not to get stuck packaging the past.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehension Debt&lt;/strong&gt; We generate understanding but don't know how to keep it as a system. And what to do about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Equilibrium&lt;/strong&gt; Architecture as a balance of forces: latency - throughput, flexibility - simplicity. Change = shift in space, invariants = boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Formula&lt;/strong&gt; Meaning is fixed, execution is computed, the system lives through the evolution of decisions.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="introduction"&gt;1. Introduction&lt;/h2&gt;

&lt;p&gt;For the last six months I've had the sense that I'm not so much writing code as trying to get a feel for the invariants of development itself.&lt;/p&gt;

&lt;p&gt;At first it looked like a local task: speed up development with AI without losing control. It seemed to be about tools - Cursor, models, pipelines.&lt;/p&gt;

&lt;p&gt;Very quickly it became clear: tools aren't the problem at all.&lt;/p&gt;

&lt;p&gt;The problem is undefined intent.&lt;/p&gt;

&lt;p&gt;AI doesn't break architecture. It just makes its weak spots visible faster than you can paper over them. You used to be able to write by hand for a week and not notice the mess in your head. Now - ten minutes, and you already have an architectural mess in the code.&lt;/p&gt;

&lt;p&gt;I stopped trying to "write faster". That's no longer the problem. AI simply removed it.&lt;/p&gt;

&lt;p&gt;The problem now is different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how well you actually understand what you're doing&lt;/li&gt;
&lt;li&gt;how well you can say it&lt;/li&gt;
&lt;li&gt;whether you have invariants, not just "seems fine"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the most interesting observation: speed is no longer the constraint. The new constraint is clarity of thinking, sharpness of invariants, the ability to formalize intent.&lt;/p&gt;

&lt;p&gt;This booklet is about where that leads: not another framework, but a shift of gravity. Code moves to the background. What we fix before code and how we keep the system within the bounds of understanding moves to the center.&lt;/p&gt;

&lt;p&gt;In short: not "how to write better", but "how to make thinking a bit more engineering". And that turned out harder than any NestJS service.&lt;/p&gt;




&lt;h2 id="code-is-not-the-center"&gt;2. Code Is Not the Center&lt;/h2&gt;

&lt;p&gt;We've lived a long time with the idea that code is the system. That if the code exists - the system exists. If we lost the code - disaster.&lt;/p&gt;

&lt;p&gt;AI quietly broke that assumption. Not loudly, not declaratively - through practice.&lt;/p&gt;

&lt;p&gt;Code became cheap. So cheap that losing it is no longer a tragedy. Not because code got worse, but because a layer above it appeared that used to be blurry.&lt;/p&gt;

&lt;p&gt;Before: idea, discussions, code, workarounds, documentation (if you're lucky).&lt;/p&gt;

&lt;p&gt;Now something else is taking shape: idea, invariants, boundaries, decision, execution, code.&lt;/p&gt;

&lt;p&gt;That's where the main shift happens: code no longer explains the system, it only reflects it.&lt;/p&gt;




&lt;p&gt;Code is not the asset. The asset is invariants and decisions.&lt;/p&gt;

&lt;p&gt;Code is their projection. You can rebuild it.&lt;/p&gt;

&lt;p&gt;If you have intent, invariants, constraints, decision graph - code becomes computable. Not in a magical sense, but in this sense: computation used to be expensive, so we fixed the result (code). Now computation is cheap - we can fix the description and rebuild the result.&lt;/p&gt;

&lt;p&gt;A handy formula:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/cimpai/cimp-practices/blob/main/templates/CHANGE_PLAN.md" rel="noopener noreferrer"&gt;CHANGE_PLAN&lt;/a&gt; / DOSA / invariants&lt;/strong&gt; - source of truth
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;code&lt;/strong&gt; - materialized view
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;execution&lt;/strong&gt; - computing system state
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're just applying to development what databases, functional systems, and distributed systems already do: schema and change log matter more than the current snapshot.&lt;/p&gt;

&lt;p&gt;One important anti-pattern: "I made it pretty but lost understanding" - that's a real anchor. So the model needs one more invariant: if you can't verify and understand the result - it's invalid, even if it's "computable".&lt;/p&gt;

&lt;p&gt;The reality of the system is slowly moving: it used to be "files + classes + functions", it's becoming "decisions + constraints + their evolution".&lt;/p&gt;




&lt;h2 id="intent-and-invariants"&gt;3. Intent and Invariants&lt;/h2&gt;

&lt;p&gt;Clean Architecture, DDD, Ports &amp;amp; Adapters - they define structure and boundaries. But the lifecycle of a decision - how it is captured, constrained, and evolved - remains implicit. The closest thing we have is &lt;a href="https://adr.github.io/" rel="noopener noreferrer"&gt;ADR&lt;/a&gt;. But &lt;a href="https://adr.github.io/" rel="noopener noreferrer"&gt;ADR&lt;/a&gt; turns decisions into documents. What we need is to turn decisions into system primitives.&lt;/p&gt;

&lt;p&gt;When you start explicitly fixing intent, invariants, constraints, kill criteria - you don't get documentation. You get a decision graph. And at some point it becomes obvious: code is not the center of the system. Code is a projection of decisions.&lt;/p&gt;

&lt;p&gt;Hence the next step. If decisions are primary, they can be versioned, checked, executed, tied to metrics. Then architecture isn't a set of layers, it's a system for managing decisions under uncertainty.&lt;/p&gt;




&lt;p&gt;In practice it looks like this. First you form the context of intent: talk to people, gather the picture. Then - a dump of thoughts, into a chat or on paper. Then structuring: not "make it pretty", but "split by intent, invariants, boundaries, steps". One plan file, one execution step at a time, a separate context per step. The model gets not "everything at once" but the minimal sufficient slice. And that gives both quality and economy: moving along meaning is cheaper than recovering meaning through search.&lt;/p&gt;

&lt;p&gt;The main observation: a separate chat - less context -&amp;gt; often better quality. LLM quality is proportional to the clarity of local context, not its size. A tree model fits: root -&amp;gt; intent and invariants, branches -&amp;gt; change plans, leaves -&amp;gt; execution steps. That's indexing by meaning, not by text.&lt;/p&gt;

&lt;p&gt;The human is responsible for meaning and boundaries. The system (AI + runtime) - for execution. AI shouldn't define the system, it should live inside the frame we set.&lt;/p&gt;




&lt;h2 id="two-modes"&gt;4. Two Modes&lt;/h2&gt;

&lt;p&gt;There are two modes we slip into when we think and do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flow / exploration.&lt;/strong&gt; That's where something new is born. No clarity, just "feels like something's here", contradiction is allowed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serialization / fixation.&lt;/strong&gt; That's where clarity, words, boundaries appear. But almost nothing new appears there anymore.&lt;/p&gt;

&lt;p&gt;The problem isn't that the second mode is bad. The problem is that it's very sticky. It gives a sense of control, completeness - "I did good, I packaged it". And you can sit in it for hours, days, and at some point catch yourself: you haven't discovered anything in a long time, you're just neatly packing the past.&lt;/p&gt;

&lt;p&gt;The key skill isn't "write better", it's switching between modes on purpose. Almost like a toggle: now I'm exploring, now I'm fixing.&lt;/p&gt;

&lt;p&gt;A strict rule helps: if you're in flow - don't try to make it pretty and correct right away. At most - short markers, anchors, scraps of thought so you can come back later. And only in a separate state: ok, now let's turn this into a plan, an article, an architecture.&lt;/p&gt;

&lt;p&gt;And an important effect: if you do it that way, serialization stops "killing the flow" and starts feeding it. You return not to a void but to a space that's already a bit structured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cimpai/cimp" rel="noopener noreferrer"&gt;CIMP&lt;/a&gt; and similar things are basically an attempt to make even the fixed part not die but stay part of a living thinking process. Not a "memory dump", but a frame you can build the next loop on.&lt;/p&gt;




&lt;h2 id="comprehension-debt"&gt;5. Comprehension Debt&lt;/h2&gt;

&lt;p&gt;You talk with someone - and it's great. But if you close the chat, half the meaning just vanishes.&lt;/p&gt;

&lt;p&gt;We generate understanding but don't know how to keep it as a system. I call this &lt;strong&gt;comprehension debt&lt;/strong&gt; - like technical debt, only in understanding. The term has been around in various circles for a long time, and I didn't coin it, but this name fits me best.&lt;/p&gt;

&lt;p&gt;Any conversation with AI is ephemeral. It doesn't persist as a knowledge system. You kind of understood - but that understanding isn't anchored anywhere. Hence ideas like RAG, context graphs, structured artifacts. But even that's not enough: knowledge isn't text, it's the link between decisions, invariants, and consequences.&lt;/p&gt;

&lt;p&gt;In the new model, documentation stops being "extra work". It becomes the main interface for controlling the system. Not an afterthought, but what execution loses its anchor without.&lt;/p&gt;

&lt;p&gt;Formulating outward - articles, posts, plans - is a way to unload your head, check what matters, and make room for new things. Not a side effect but a natural extension of the same approach: structure lowers the cognitive cost.&lt;/p&gt;

&lt;p&gt;One more thought: if you can't hold the system as a model - it doesn't exist. Doesn't matter how many lines of code. So fixing meaning isn't bureaucracy, it's the condition for the system to exist in your head and in the heads of everyone who works with it.&lt;/p&gt;




&lt;h2 id="equilibrium"&gt;6. Equilibrium&lt;/h2&gt;

&lt;p&gt;Architecture works with a limited set of concepts and meanings. They're almost deterministic, what changes is mainly context. And there are concrete forces that are always being traded off.&lt;/p&gt;

&lt;p&gt;Technical: compute vs data, latency vs throughput, consistency and availability.&lt;/p&gt;

&lt;p&gt;Structural: flexibility vs simplicity, experimentation and research vs control.&lt;/p&gt;

&lt;p&gt;Architecture isn't a choice of "what's better", it's equilibrium. Every change isn't a "feature", it's a shift of the system in the space of these forces. And if you have invariants, you limit where you can move. If you don't - the system just spreads.&lt;/p&gt;

&lt;p&gt;It helps to think of it as vectors. The system is a point in the space of forces, a change is a shift of the vector, invariants are constraints on the allowed region. You start to see that system architecture and model architecture (the same vectors, matrices, parallel computation) aren't different worlds - they're the same math in different guises.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/uxter/stop-using-llms-for-everything-the-power-of-hybrid-architectures-45ee"&gt;Splitting into two layers&lt;/a&gt; keeps the zones from mixing: deterministic (invariants, policies, boundaries, checkable rules) and probabilistic (AI, inference, generation, search). AI should live inside constraints, not define them. Then the human is responsible for meaning and boundaries, the system for execution.&lt;/p&gt;

&lt;p&gt;In the end, development isn't writing code, it's managing the computation of decisions. And your workflow with plans, steps, and review stops looking like a hack and starts looking like a clean model: you generate intent, fix it, split into steps, execute one at a time, check, adjust. The main thing: you don't hold everything in your head at once. You build a system where moving along meaning is cheaper than recovering it.&lt;/p&gt;




&lt;h2 id="one-formula"&gt;7. One Formula&lt;/h2&gt;

&lt;p&gt;If you pack it all into one short formula:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaning is fixed. Execution is computed. The system lives through the evolution of decisions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're no longer trying to "write correctly". You're trying to make it so that even if you forget - the system can be restored. That's already very close to how math, physics, and stable systems in general work.&lt;/p&gt;

&lt;p&gt;The shift is essentially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;was:&lt;/strong&gt; code-centric engineering
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;becomes:&lt;/strong&gt; decision-centric engineering
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like git for code - only for decisions. At some point I realized architecture isn't about diagrams. It's about taking a blurry thought and making it concrete enough to be checked, executed, and not lost a week later.&lt;/p&gt;

&lt;p&gt;The final picture: not "speed up development", but make it observable, explainable, controllable, and scalable without losing meaning. Thinking becomes executable. And that's much deeper than it seems at first.&lt;/p&gt;




&lt;p&gt;This idea doesn't stop here.&lt;/p&gt;

&lt;p&gt;If code is not the source of truth, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what is?&lt;/li&gt;
&lt;li&gt;how is it structured?&lt;/li&gt;
&lt;li&gt;how does it evolve?&lt;/li&gt;
&lt;/ul&gt;

&lt;p id="next-parts"&gt;I'll explore this in the next short parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DOSA (Decision-Oriented System Architecture)&lt;/strong&gt; - what happens when decisions become first-class system primitives, and architecture turns into a graph of evolving decisions rather than static structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context-oriented engineering&lt;/strong&gt; - why smaller, structured context outperforms large prompts, and how to make context composable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback-centric engineering&lt;/strong&gt; - how systems close the loop between execution and understanding, and learn through decisions
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System evolution&lt;/strong&gt; - how systems become capable of change while preserving stability&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>discuss</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Stop Using LLMs for Everything: The Power of Hybrid Architectures</title>
      <dc:creator>Vasiliy Shilov</dc:creator>
      <pubDate>Sun, 08 Mar 2026 19:40:10 +0000</pubDate>
      <link>https://dev.to/uxter/stop-using-llms-for-everything-the-power-of-hybrid-architectures-45ee</link>
      <guid>https://dev.to/uxter/stop-using-llms-for-everything-the-power-of-hybrid-architectures-45ee</guid>
      <description>&lt;p&gt;Over the past month my thinking about AI systems changed dramatically.&lt;/p&gt;

&lt;p&gt;Many teams are quietly making the same architectural mistake:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They use LLMs for problems that should remain deterministic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The result is predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;higher latency&lt;/li&gt;
&lt;li&gt;higher cost&lt;/li&gt;
&lt;li&gt;lower reliability&lt;/li&gt;
&lt;li&gt;harder debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The irony?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most intelligent systems don't need more AI. They need better architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The common narrative today is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intelligence = large probabilistic models.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This assumption quietly pushes many teams into a dangerous design mistake: using probabilistic models for problems that should remain deterministic.&lt;/p&gt;

&lt;p&gt;But when you start building systems that actually work reliably, a different picture appears.&lt;/p&gt;

&lt;p&gt;Most practical systems are not purely probabilistic — they are architectures combining deterministic and probabilistic computation.&lt;/p&gt;

&lt;p&gt;Understanding the difference between these two classes of computation turns out to be extremely important, not only for AI engineers but for system architects in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Idea Came From
&lt;/h2&gt;

&lt;p&gt;My perspective on this topic evolved through several stages.&lt;/p&gt;

&lt;p&gt;First, years of writing software the traditional way — carefully designing deterministic systems where behavior is predictable and constraints are explicit.&lt;/p&gt;

&lt;p&gt;Then the arrival of AI coding tools. Suddenly code generation became extremely cheap. Many tasks that used to require careful implementation could be produced instantly.&lt;/p&gt;

&lt;p&gt;At first this felt like pure acceleration. But over time it became clear that cheap execution has a side effect: architectural drift.&lt;/p&gt;

&lt;p&gt;This line of thinking started when I began exploring the hidden cost of cheap execution in AI-accelerated development (which I wrote about earlier in a LinkedIn post: "&lt;a href="https://www.linkedin.com/pulse/hidden-cost-cheap-execution-vasiliy-shilov-6o1qf/" rel="noopener noreferrer"&gt;The Hidden Cost of Cheap Execution&lt;/a&gt;").&lt;/p&gt;

&lt;p&gt;More recently I've been building tools that intentionally combine deterministic and probabilistic computation — applying probabilistic reasoning only where deterministic structure cannot reduce the problem space further.&lt;/p&gt;

&lt;p&gt;This article summarizes the core principle behind that approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Classes of Computation
&lt;/h2&gt;

&lt;p&gt;At a very high level, most computational tasks fall into two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deterministic computation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Probabilistic computation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They solve fundamentally different kinds of problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Deterministic&lt;/th&gt;
&lt;th&gt;Probabilistic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;fixed&lt;/td&gt;
&lt;td&gt;distribution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;straightforward&lt;/td&gt;
&lt;td&gt;statistical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure&lt;/td&gt;
&lt;td&gt;explicit&lt;/td&gt;
&lt;td&gt;uncertain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;cheap&lt;/td&gt;
&lt;td&gt;expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use case&lt;/td&gt;
&lt;td&gt;constraints&lt;/td&gt;
&lt;td&gt;ambiguity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Deterministic Computation
&lt;/h2&gt;

&lt;p&gt;Deterministic computation is what classical software engineering is built on. Given the same input, the system always produces the same output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compilers&lt;/li&gt;
&lt;li&gt;parsers&lt;/li&gt;
&lt;li&gt;type checkers&lt;/li&gt;
&lt;li&gt;database queries&lt;/li&gt;
&lt;li&gt;validation rules&lt;/li&gt;
&lt;li&gt;cryptography&lt;/li&gt;
&lt;li&gt;routing logic&lt;/li&gt;
&lt;li&gt;protocol implementations&lt;/li&gt;
&lt;li&gt;regular expressions (parsing, validation, extraction)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In deterministic systems:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;output = f(input)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The function &lt;em&gt;f&lt;/em&gt; is explicit, stable, and predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strengths
&lt;/h3&gt;

&lt;p&gt;Deterministic computation is extremely powerful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rules are known&lt;/li&gt;
&lt;li&gt;constraints are strict&lt;/li&gt;
&lt;li&gt;correctness matters&lt;/li&gt;
&lt;li&gt;behavior must be explainable&lt;/li&gt;
&lt;li&gt;failure modes must be controlled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Properties:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;predictable&lt;/li&gt;
&lt;li&gt;debuggable&lt;/li&gt;
&lt;li&gt;verifiable&lt;/li&gt;
&lt;li&gt;cheap to run&lt;/li&gt;
&lt;li&gt;safe for critical paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why the core infrastructure of the digital world — databases, compilers, operating systems — is deterministic. No surprises. You can reason about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;Deterministic systems struggle when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rules are unknown&lt;/li&gt;
&lt;li&gt;inputs are ambiguous&lt;/li&gt;
&lt;li&gt;the space of possibilities is huge&lt;/li&gt;
&lt;li&gt;knowledge must be compressed from data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;natural language interpretation&lt;/li&gt;
&lt;li&gt;image recognition&lt;/li&gt;
&lt;li&gt;semantic similarity&lt;/li&gt;
&lt;li&gt;reasoning under uncertainty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems are hard to encode with explicit rules. That's where probability earns its place.&lt;/p&gt;




&lt;h2&gt;
  
  
  Probabilistic Computation
&lt;/h2&gt;

&lt;p&gt;Probabilistic systems operate differently. Instead of explicit rules, they model probability distributions.&lt;/p&gt;

&lt;p&gt;For example, a language model estimates:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P(next_token | context)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The system does not compute the answer through rules; it computes the most likely continuation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;language models&lt;/li&gt;
&lt;li&gt;speech recognition&lt;/li&gt;
&lt;li&gt;recommender systems&lt;/li&gt;
&lt;li&gt;ranking models&lt;/li&gt;
&lt;li&gt;anomaly detection&lt;/li&gt;
&lt;li&gt;computer vision models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probabilistic systems are extremely powerful for problems where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rules are unknown&lt;/li&gt;
&lt;li&gt;data is noisy&lt;/li&gt;
&lt;li&gt;patterns must be inferred&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Strengths
&lt;/h3&gt;

&lt;p&gt;Probabilistic systems are excellent at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pattern recognition&lt;/li&gt;
&lt;li&gt;generalization&lt;/li&gt;
&lt;li&gt;handling ambiguity&lt;/li&gt;
&lt;li&gt;synthesizing new combinations&lt;/li&gt;
&lt;li&gt;compressing large knowledge spaces&lt;/li&gt;
&lt;li&gt;when you don't have a spec, they're often the only option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why modern AI works at all. The catch: it doesn't tell you &lt;em&gt;where&lt;/em&gt; to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;But probabilistic systems have fundamental weaknesses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;non-deterministic outputs&lt;/li&gt;
&lt;li&gt;hallucinations&lt;/li&gt;
&lt;li&gt;difficulty enforcing constraints&lt;/li&gt;
&lt;li&gt;limited explainability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cost and latency&lt;/strong&gt; — model inference is expensive compared to deterministic logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A regex, an if statement, or a database lookup executes in microseconds and costs essentially nothing. A model call costs money and introduces latency. At scale, this difference becomes a primary architectural constraint.&lt;/p&gt;

&lt;p&gt;If used incorrectly, they introduce uncertainty into places where certainty is required.&lt;/p&gt;




&lt;h2&gt;
  
  
  The False Dichotomy
&lt;/h2&gt;

&lt;p&gt;Many discussions today frame the problem incorrectly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should we replace deterministic systems with AI?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the wrong question. The real question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should deterministic and probabilistic computation be composed?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Deterministic Computation Wins
&lt;/h2&gt;

&lt;p&gt;Deterministic systems dominate when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the structure is known&lt;/li&gt;
&lt;li&gt;constraints exist&lt;/li&gt;
&lt;li&gt;invariants must be preserved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Programming languages&lt;/strong&gt; — Compilers are deterministic for a reason. A probabilistic compiler would be catastrophic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt; — SQL engines are deterministic because queries must be correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocols&lt;/strong&gt; — Network protocols rely on deterministic state machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt; — Formats like JSON, protobuf, and schema validation require exact correctness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular expressions&lt;/strong&gt; — Same pattern and input always yield the same match. In hybrid systems they often do the first cut — extracting structure (dates, IDs, emails) from raw text before any LLM sees it. That reduces ambiguity and keeps the model away from tasks that don't need probability.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where Probabilistic Computation Wins
&lt;/h2&gt;

&lt;p&gt;Probabilistic systems dominate when the problem is inherently ambiguous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Natural language&lt;/strong&gt; — Human language contains ambiguity everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval and ranking&lt;/strong&gt; — Choosing the most relevant document is rarely deterministic. Ever tried to make that 100% rule-based? It doesn't scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vision&lt;/strong&gt; — Images are noisy and high dimensional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code synthesis&lt;/strong&gt; — Generating new code often requires combining patterns probabilistically.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Deterministic Risk Control
&lt;/h2&gt;

&lt;p&gt;Deterministic layers are where you enforce invariants and reduce risk. Probabilistic components don't get to override these rules.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input validation&lt;/strong&gt; — length, charset, schema (e.g. JSON schema). Invalid input never reaches the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output validation&lt;/strong&gt; — allowlists of actions, formats, or categories; length limits; PII checks. The model may suggest something, but only allowed values are executed or stored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular expressions&lt;/strong&gt; — extract and validate structure (emails, IDs, tags) before the model; same for checking model output against expected patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit and idempotency&lt;/strong&gt; — deterministic request IDs and idempotency keys ensure that critical actions are logged and not duplicated, regardless of model non-determinism.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've seen codebases that sent every user message straight to an LLM. The bill and the latency told the story.&lt;/p&gt;

&lt;p&gt;The rule of thumb: &lt;em&gt;anything that would cause legal, safety, or data-integrity issues must be enforced in deterministic code&lt;/em&gt;, not in prompt engineering or "smarter" models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: deterministic extraction before any LLM call:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;extractStructuredParts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;ticketIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;hasUrgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\w&lt;/span&gt;&lt;span class="sr"&gt;.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[\w&lt;/span&gt;&lt;span class="sr"&gt;.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.\w&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ticketRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/#&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urgentRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b(&lt;/span&gt;&lt;span class="sr"&gt;urgent|asap|critical&lt;/span&gt;&lt;span class="se"&gt;)\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailRegex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;ticketIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticketRegex&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="na"&gt;hasUrgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;urgentRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Same input =&amp;gt; same output. No model needed for this.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example: deterministic guardrails on model output&lt;/strong&gt; — only allowlisted actions are executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ALLOWED_ACTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safeExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modelOutput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modelOutput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// e.g. "submit form"&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ALLOWED_ACTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: unknown action&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// never pass through raw model output&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;executeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Real Architecture: Hybrid Systems
&lt;/h2&gt;

&lt;p&gt;The most powerful systems are hybrid. Instead of replacing deterministic computation, probabilistic models should operate inside deterministic scaffolding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deterministic logic defines the boundaries. Probabilistic models explore inside those boundaries.&lt;/strong&gt; That is the metaphor worth keeping in mind.&lt;/p&gt;

&lt;p&gt;Conceptually, the flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          Problem Space

┌──────────────────────────────┐
│                              │
│   Deterministic Reduction    │
│  (rules, validation, index)  │
│                              │
└──────────────┬───────────────┘
               │
               ▼
      Residual Uncertainty
               │
               ▼
     Probabilistic Reasoning
        (LLM / ML models)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Good architecture reduces the problem space deterministically before applying probabilistic intelligence.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A typical pipeline in code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input
   │
   ▼
deterministic preprocessing
   │
   ▼
constraint reduction
   │
   ▼
retrieval / memory
   │
   ▼
probabilistic reasoning
   │
   ▼
deterministic validation
   │
   ▼
output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In code, that often looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Hybrid: deterministic shell around probabilistic core&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processUserRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Deterministic: normalize and validate input&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid length&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Deterministic: extract known structure (e.g. with regex)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/#&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// ticket IDs&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Probabilistic: only for the ambiguous part&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Deterministic: validate output shape and safety&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fallbackResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove everything that can be solved deterministically.&lt;/li&gt;
&lt;li&gt;Narrow the search space.&lt;/li&gt;
&lt;li&gt;Retrieve known information.&lt;/li&gt;
&lt;li&gt;Use probabilistic reasoning only for the residual uncertainty.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Ports and Adapters: Structure Decides
&lt;/h3&gt;

&lt;p&gt;The same pipeline fits naturally into a port-adapter (hexagonal) view. What matters is the &lt;strong&gt;structure&lt;/strong&gt; — the ports and the flow — not whether a given step is implemented deterministically or probabilistically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          ┌─────────────────────────────────────┐
          │         Application Core            │
          │  (orchestration, use cases, ports)  │
          └──────────────────┬──────────────────┘
                             │
     ┌───────────────────────┼────────────────────────┐
     │                       │                        │
     ▼                       ▼                        ▼
┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ ┌─────────┐
│ Preproc │ │ Retrieve │ │ Reason │ │ Validate │ │  Output │
│  port   │ │  port    │ │  port  │ │  port    │ │  port   │
└────┬────┘ └────┬─────┘ └────┬───┘ └────┬─────┘ └────┬────┘
     │           │            │          │            │
     ▼           ▼            ▼          ▼            ▼
  adapter     adapter      adapter     adapter      adapter
  (determ.    (vector DB,  (LLM /      (schema,     (format,
  or LLM)     or rule)     or rules)   allowlist)   log)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core depends only on &lt;strong&gt;ports&lt;/strong&gt; (interfaces). Each adapter can be deterministic or probabilistic. You can replace a deterministic preprocessor with a probabilistic one (e.g. "normalize with an LLM") or the other way around — the architecture stays the same. &lt;strong&gt;Structure decides; implementations are pluggable.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Port: the core only depends on this contract&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ReasonerPort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Adapter A: deterministic (rules, template)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RuleBasedReasoner&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ReasonerPort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;applyTemplates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// same input =&amp;gt; same output&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Adapter B: probabilistic (LLM)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LLMReasoner&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;ReasonerPort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;refs&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// same input =&amp;gt; may vary&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Application code is identical; swap the adapter to switch behaviour&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reasoner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReasonerPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RuleBasedReasoner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// or new LLMReasoner()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So: the &lt;strong&gt;decision&lt;/strong&gt; of where to use deterministic vs probabilistic logic lives in the choice of adapters, not in the core. The core defines &lt;em&gt;what&lt;/em&gt; steps exist and in what order — that is what we mean by "architecture is the multiplier."&lt;/p&gt;




&lt;h2&gt;
  
  
  Residual Intelligence
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Residual Intelligence Principle
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Probabilistic models should solve only the residual uncertainty after deterministic reduction of the problem space.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Good architecture does not ask AI to solve everything. It asks AI to solve only what cannot be solved deterministically. Get that wrong and you're paying for intelligence you don't need.&lt;/p&gt;

&lt;p&gt;This dramatically reduces complexity and leads to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cheaper systems&lt;/li&gt;
&lt;li&gt;more reliable outputs&lt;/li&gt;
&lt;li&gt;fewer hallucinations&lt;/li&gt;
&lt;li&gt;easier governance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Code Completion
&lt;/h3&gt;

&lt;p&gt;Modern IDEs illustrate this hybrid approach well. Many completions do not require LLMs. They rely on deterministic information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;syntax&lt;/li&gt;
&lt;li&gt;types&lt;/li&gt;
&lt;li&gt;symbol tables&lt;/li&gt;
&lt;li&gt;project index&lt;/li&gt;
&lt;li&gt;scope rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only when the system cannot determine a clear continuation does it use probabilistic generation. This combination is far more efficient than using an LLM everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extreme Cases
&lt;/h2&gt;

&lt;p&gt;Understanding the extremes is also instructive: pure deterministic systems suffer from rule explosion, pure probabilistic ones from uncontrolled uncertainty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pure deterministic systems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Strengths:&lt;/em&gt; reliability, predictability, efficiency&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Weaknesses:&lt;/em&gt; brittleness, inability to generalize, enormous rule complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pure probabilistic systems&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Strengths:&lt;/em&gt; flexibility, adaptability, pattern recognition&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Weaknesses:&lt;/em&gt; instability, hallucinations, lack of guarantees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most systems that "went full AI" learned that the hard way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Is the Multiplier
&lt;/h2&gt;

&lt;p&gt;The biggest performance gains rarely come from making probabilistic models bigger. They come from structuring the system correctly.&lt;/p&gt;

&lt;p&gt;A well-designed deterministic layer can reduce the search space by orders of magnitude, so the probabilistic layer works on a much smaller and easier problem — and that is where nonlinear efficiency gains appear. One good deterministic filter can shrink the problem tenfold before the model ever runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Different Way to Think About AI
&lt;/h2&gt;

&lt;p&gt;Instead of thinking about AI as a replacement for software engineering, we can think about it as a new computational layer.&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;software =&amp;gt; replaced by AI&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deterministic systems
      +
probabilistic models
      =
hybrid intelligent architectures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The future of intelligent systems is likely not pure AI; it is architecture — the art of deciding which parts of the system must be deterministic, and where probability should be allowed to exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thought
&lt;/h2&gt;

&lt;p&gt;AI did not eliminate engineering. It exposed something deeper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution was never the hardest problem.&lt;/strong&gt; The real challenge has always been structuring the problem space so that expensive intelligence is used only where it is truly needed. That is the job of architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  One question
&lt;/h2&gt;

&lt;p&gt;If you removed all deterministic layers from your system and replaced them with LLM calls...&lt;/p&gt;

&lt;p&gt;would it become smarter — or just more expensive?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>systemdesign</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Clean Architecture in the Age of AI: Preventing Architectural Liquefaction</title>
      <dc:creator>Vasiliy Shilov</dc:creator>
      <pubDate>Mon, 02 Mar 2026 00:21:21 +0000</pubDate>
      <link>https://dev.to/uxter/clean-architecture-in-the-age-of-ai-preventing-architectural-liquefaction-5d8d</link>
      <guid>https://dev.to/uxter/clean-architecture-in-the-age-of-ai-preventing-architectural-liquefaction-5d8d</guid>
      <description>&lt;p&gt;AI has made execution cheap; models optimize locally, not for architecture. In many teams the side effect is not bad code or broken builds, but something more structural: &lt;strong&gt;architectural liquefaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Architectural liquefaction&lt;/em&gt; is the progressive loss of structural boundaries under sustained probabilistic code generation and accelerated change cycles. It does not happen in one PR — layer boundaries soften, dependencies cross the wrong way, contracts drift, invariants weaken, "temporary" shortcuts pile up. Everything still works. Until the cost of change quietly multiplies. Without explicit constraints, entropy grows as we ship faster.&lt;/p&gt;

&lt;p&gt;Clean Architecture is often described as a layering discipline. But in the context of AI-assisted development, it may serve a different purpose: a &lt;em&gt;deterministic shell&lt;/em&gt; around probabilistic execution. Not dogma, not aesthetic preference — a stabilizing mechanism. When boundaries are explicit and dependency direction is enforced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The solution space &lt;strong&gt;narrows&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Drift becomes &lt;strong&gt;detectable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Structural violations &lt;strong&gt;surface earlier&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Local optimization cannot silently destroy global design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture becomes a &lt;strong&gt;control surface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before AI, architectural violations required effort. A developer had to consciously decide to break a boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;, violations can be generated in seconds.&lt;/p&gt;

&lt;p&gt;And because AI-generated code often "looks right", structural erosion is harder to notice. The real cost is not bad code in the moment; it's that the drift stays invisible until you hit a refactor that suddenly touches half the codebase. One more thing: the more “flexible” and underspecified your prompts and rules are, the faster liquefaction tends to happen — the model fills in the gaps in whatever direction is locally easiest.&lt;/p&gt;

&lt;p&gt;I once wrote down all our architectural principles — boundaries, dependency rules, what lives where — into a &lt;code&gt;docs/&lt;/code&gt; folder in plain Markdown, then wired them into Cursor as project rules so they get injected into every prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tree ./docs/
&lt;span class="nb"&gt;.&lt;/span&gt;
├── ARCHITECTURAL-STYLE-GUIDE.md
├── CLEAN-NEST-APP.md
├── architecture
│   ├── adapters.md
│   ├── core.md
│   ├── controllers.md
│   ├── events.md
│   ├── inter-module-communication.md
│   ├── modules.md
│   ├── structure.md
│   ├── testing.md
│   └── when-to-simplify.md
└── guides
    ├── cheat-sheet.md
    ├── common-patterns.md
    └── quick-start.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before that, Cursor would often put repository calls straight into controllers or leak infrastructure imports into the domain layer — it just followed the patterns it saw in the codebase. After the rules were in place, it started routing through use cases and keeping adapters out of core. Still not perfect: sometimes it over-engineers or picks the wrong abstraction. But the rate of cross-layer violations dropped sharply. The model had something to optimize &lt;em&gt;for&lt;/em&gt; instead of only optimizing for "code that runs".&lt;/p&gt;

&lt;p&gt;That is one data point. It fits the hypothesis: &lt;strong&gt;explicit boundaries plus enforcement reduce structural drift&lt;/strong&gt;, even when the code is AI-generated.&lt;/p&gt;

&lt;p&gt;To make this testable we'd need drift metrics (e.g. dependency violations, cross-layer calls), review cost over time, and refactor scope when fixing violations. The hypothesis would be falsified if teams with strict rules drift as much as others, or if review and refactor cost keep growing despite enforcement. I'm preparing concrete ways to define and track these — drift metrics and cost — for follow-up posts.&lt;/p&gt;

&lt;p&gt;Clean Architecture is usually framed as boundaries, inward dependencies, business logic isolated from the rest. True enough — but in an AI-heavy workflow the useful way to see it is: &lt;em&gt;probabilistic execution, deterministic governance&lt;/em&gt;. We are not removing uncertainty. We are putting a box around it so that the model's choices stay inside the box. The architecture becomes the box.&lt;/p&gt;

&lt;p&gt;If you are using AI heavily in development: are your boundaries getting stronger or weaker? Is the cost of keeping the structure in your head going up or down? I don't have a conclusion yet — only a hypothesis. AI has optimized execution; whether we've optimized stability, or are just producing entropy faster, is open. Obvious structures are often the first to dissolve when everything speeds up. In the next posts I'll look at other ways to keep things from liquefying.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cleanarchitecture</category>
      <category>ai</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
