<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ali Ahmed Thawerani</title>
    <description>I am a passionate developer with experience in building web applications using modern technologies.</description>
    <link>https://aathawerani.github.io/</link>
    <atom:link href="https://aathawerani.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 31 Oct 2026 17:45:45 +0000</pubDate>
    <lastBuildDate>Sat, 31 Oct 2026 17:45:45 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>

    
      <item>
        <title>A Requirement Rather Than a Reality</title>
        <description>&lt;p&gt;I gave a guest lecture this week on software requirements and design: what happens to the SRS and the SDS when AI agents write much of the code. We covered specifications, architecture decision records, C4 diagrams and automated guardrails. Somewhere in the middle I realised I had skipped something more basic. I had presented spec-driven development as the natural way to work with agents, and never stopped to compare it with the way many people actually work with them today: describe what you want, accept what comes back, and keep going until it runs.&lt;/p&gt;

&lt;p&gt;Thinking about that gap afterwards, I found the real question was not about tools at all. It was about what we mean by &lt;em&gt;engineering&lt;/em&gt;. This post is my attempt to think it through. It is an opinion, not advice, and I hold it loosely.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-requirement-rather-than-a-reality&quot;&gt;A requirement rather than a reality&lt;/h2&gt;

&lt;p&gt;The phrase &lt;em&gt;software engineering&lt;/em&gt; is younger than many of the people who use it. It was popularised at a NATO conference in Garmisch, Germany, in October 1968, called because large software projects kept arriving late, over budget and unreliable. Some of the participants were willing to call it a “software crisis.”&lt;/p&gt;

&lt;p&gt;Brian Randell, who was there and co-edited the conference report, looked back fifty years later. The title, he wrote, had been chosen deliberately to be provocative, “describing a requirement rather than a reality,” and he credits the choice to Fritz Bauer &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I find that phrase humbling. Engineering discipline was never something software simply had. It was something the field decided it needed, because too much was falling through the cracks. Testing and design reviews already existed in some form, but requirements engineering, systematic reviews, configuration management and change control became, over the following decades, the field’s way of trying to make that aspiration real.&lt;/p&gt;

&lt;p&gt;That is the lens I want to use for vibe coding. The question is not whether AI is good or bad for software. It is whether a new way of working keeps the aspiration, or quietly drops it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-the-discipline-is-actually-for&quot;&gt;What the discipline is actually for&lt;/h2&gt;

&lt;p&gt;“Discipline” can sound like a virtue word, so it is worth being concrete about what it does.&lt;/p&gt;

&lt;p&gt;Most of the practices we call engineering exist for one reason: &lt;strong&gt;to catch what a single person’s attention misses.&lt;/strong&gt; Each one is a net. None is perfect, but together they mean that a mistake has to slip through several independent checks before it reaches production.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/requirement-not-reality/discipline-nets.svg&quot; alt=&quot;Engineering practices as four nets hanging from a person who understands the code; in a vibe-coded system the nets remain but the person is missing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is a long-standing reason these nets matter so much. Robert Glass collected the evidence decades ago: historically, maintenance has consumed 40 to 80 percent of software costs, about 60 percent on average, and the single largest maintenance activity is simply understanding the existing code &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. Manny Lehman’s first law of software evolution adds that software used in the real world must keep changing or become progressively less useful &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;. Software is read and changed far more than it is written. The discipline exists largely for those later readers.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-vibe-coding-removes&quot;&gt;What vibe coding removes&lt;/h2&gt;

&lt;p&gt;The term &lt;em&gt;vibe coding&lt;/em&gt; comes from Andrej Karpathy, who described in February 2025 “a new kind of coding … where you fully give in to the vibes, embrace exponentials, and forget that the code even exists” &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;. He was clear about where it belonged: “not too bad for throwaway weekend projects.”&lt;/p&gt;

&lt;p&gt;Simon Willison gave the clearest definition I have found: vibe coding is “building software with an LLM without reviewing the code it writes” &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;. He is equally clear about what it is not. If an LLM wrote every line but you reviewed it, tested it and can explain it to someone else, that is not vibe coding; it is software development. His own rule is that he will not commit code he could not explain to somebody else. Martin Fowler draws the same line &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is why I think the usual framing, “AI coding versus traditional coding,” misses the point. Using AI heavily is not the problem. Teams can and do use AI to write most of their code while keeping every net in place.&lt;/p&gt;

&lt;p&gt;What vibe coding removes is more basic than any single practice. Code review assumes there is an author who understood the code, and adds a second reader. Vibe coding removes the &lt;em&gt;first&lt;/em&gt; reader: not the model, which has certainly processed the code, but the person who can explain what it does, question its assumptions and take responsibility for its behaviour. Tests can still run, but unless someone has checked what they assert against the actual requirements, they may faithfully verify the wrong interpretation. The nets are still hanging there, but the person they were tied to is gone.&lt;/p&gt;

&lt;p&gt;I should be fair to the strongest objection here. Reading every line by hand is not the only way to gain confidence in software. Behavioural and property-based tests, static analysis, independent review, observability and staged releases all produce evidence about whether a system works, and a team can lean on them heavily. I agree. But evidence still needs someone to judge it: someone who understands the system well enough to know whether the tests check the right things, and who has the authority to say the business rule itself is right. Those are not always the same person; an engineer may understand the code perfectly without being able to confirm the rule, and a product owner may own the rule without being able to read the code. What I am really arguing for is not line-by-line reading. It is that, for anything that matters, someone accountable has understood what was built and the evidence that it works.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-much-discipline-does-a-system-need&quot;&gt;How much discipline does a system need?&lt;/h2&gt;

&lt;p&gt;None of this means every line of code deserves full ceremony. A demo for tomorrow’s meeting does not need traceability or change control. Discipline has a real cost, and spending it where nothing can fall far is waste.&lt;/p&gt;

&lt;p&gt;My instinct is that the amount of discipline a system needs depends on two things: &lt;strong&gt;how long it will live&lt;/strong&gt;, and &lt;strong&gt;what it touches&lt;/strong&gt;, which is really a question of what happens if it fails. A script that runs once sounds disposable, until it is the script that migrates a bank’s ledger records.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/requirement-not-reality/discipline-dimensions.svg&quot; alt=&quot;A two-by-two of how long a system will live against what its failure costs, with a one-time bank project drifting into the long-lived, consequential corner&quot; /&gt;&lt;/p&gt;

&lt;p&gt;How long it lives is where the difference between project companies and product companies comes in. A project delivered once might survive vibe coding, and the speed might genuinely help it win. A product shipped release after release for years is read and changed by people who did not write it, which is exactly where Glass’s numbers bite.&lt;/p&gt;

&lt;p&gt;Even here, though, I have learned to be careful:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Few projects are as one-time as they look.&lt;/strong&gt; Warranty periods, change requests and maintenance contracts mean that a system built as a project for a bank can still be running a decade later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;In a project, the cost does not disappear; it moves.&lt;/strong&gt; The team that delivered moves on, and whoever maintains the system next, often the client’s own team, inherits code that nobody ever read.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;It may close the road from project to product.&lt;/strong&gt; In &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;&lt;em&gt;The Inevitable Cycles&lt;/em&gt;&lt;/a&gt; I described how software houses usually become product companies: similar projects repeat, teams notice common components, and reuse gradually becomes a product &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;. That depends on someone understanding the projects well enough to see what they share. If nobody read the code, there is nothing to harvest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What the system touches is the second dimension, and it is where my own field sits at the extreme.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;in-fintech-the-discipline-is-written-down&quot;&gt;In fintech, the discipline is written down&lt;/h2&gt;

&lt;p&gt;In payments, “nothing falls through the cracks” is not a figure of speech. A crack is a debit with no matching credit, a reversal applied twice, a transaction the ledger says failed while the bank says it succeeded. In &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;&lt;em&gt;The Hollow Sprint&lt;/em&gt;&lt;/a&gt; I used the example of a wallet that assumes a switch timeout means the debit failed: once that assumption has shaped the ledger, the reconciliation job, the customer notification and the settlement file, correcting it is no longer a small change &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. Those are exactly the cases the engineering nets exist to catch, and exactly the cases that only appear when someone thinks carefully about what can go wrong.&lt;/p&gt;

&lt;p&gt;In this domain the discipline is also not left to taste. Take the card industry’s security standard. PCI DSS version 4.0.1 requires that bespoke and custom software is reviewed before it is released to production, to find and correct coding vulnerabilities (Requirement 6.2.3). Where those reviews are manual, code changes must be “reviewed by individuals other than the originating code author” and approved by management before release (Requirement 6.2.3.1) &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I want to be careful about what the standard does and does not say. It does not prescribe how much code a person must write, and it does not say the originating author must have written or understood every line. Its concern is that software is reviewed before release and, where reviews are manual, that the review is independent and approved. Whether a vibe-coded module can pass an audit depends on how a particular organisation implements its controls.&lt;/p&gt;

&lt;p&gt;My concern is the one underneath. When most of an implementation is generated, who can explain its assumptions, judge whether the review was meaningful, and take responsibility for the result? Complying with a review requirement and genuinely understanding the code are related, but they are not the same thing. Still, the direction of the standard is clear: in fintech, the 1968 aspiration has become, at least in places, a written obligation.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-vibe-coding-belongs&quot;&gt;Where vibe coding belongs&lt;/h2&gt;

&lt;p&gt;None of this makes vibe coding useless. I think it has a proper place, and it is at the very beginning.&lt;/p&gt;

&lt;p&gt;Customers are often much better at reacting to something they can see than at describing what they want. Requirements engineering has known this for a long time: Karl Wiegers and Joy Beatty distinguish &lt;em&gt;throwaway&lt;/em&gt; prototypes, built to learn and then discarded, from &lt;em&gt;evolutionary&lt;/em&gt; prototypes that grow into the product &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;. Fred Brooks put the older version more bluntly: “plan to throw one away; you will, anyhow” &lt;a href=&quot;#ref-11&quot;&gt;[11]&lt;/a&gt;. What vibe coding changes is the cost. A throwaway prototype that once took weeks can now be produced in an afternoon, with the customer in the room. In &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;&lt;em&gt;The Hollow Sprint&lt;/em&gt;&lt;/a&gt; I suggested exactly this for uncertain decisions: build the visible part with the customer, keep the confirmed decisions, and throw the prototype away &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The important words there are &lt;em&gt;throw the prototype away&lt;/em&gt;. What should survive a vibe-coded prototype is not its code but the decisions it helped people make, written down where they can be checked.&lt;/p&gt;

&lt;p&gt;This is also where my earlier post on &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;technology stack selection&lt;/a&gt; comes back in, with a caveat against myself &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;. In that post I argued that starting in a stack where AI tools are strongest is sensible, and that a product can later move parts of itself to the stack its domain demands, as fintech cores often drift towards ecosystems with stronger compliance tooling. But I also wrote that “the prototype built with speed but no structural discipline tends to become the thing that blocks future progress — not because it failed, but because it succeeded.” Those later migrations only stay small because the prototype had clean seams from the first day: domain modules, one interface file per external service, an architecture file the agent reads.&lt;/p&gt;

&lt;p&gt;A vibe-coded prototype has none of those seams. That is fine if it really is thrown away. The danger is the prototype that impresses the customer and quietly becomes version one. Then nobody ever chose the stack deliberately, and there is no clean seam to migrate along.&lt;/p&gt;

&lt;p&gt;So the shape I keep coming back to has three phases: vibe-coded discovery, a deliberate break, and disciplined product development.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/requirement-not-reality/three-phases.svg&quot; alt=&quot;Three phases: discovery, a deliberate break where decisions, open questions, rejected options and examples are carried across while unreviewed code is left behind, then product development&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Two details matter. In fintech, discovery should use fake data only; a prototype holding real customer or card data inherits the product’s obligations. And “throw it away” is a default, not a rule: code that has genuinely been reviewed and tested to production standards can be reused on that evidence. What should not cross the break is code nobody has read, simply because it already works.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-signed-document-we-gave-up&quot;&gt;The signed document we gave up&lt;/h2&gt;

&lt;p&gt;That brings me to something I talked about in the lecture without having planned to.&lt;/p&gt;

&lt;p&gt;For most of my career, a project began with a detailed functional specification or SRS. The customer read it, argued over it and signed it. It was not only a technical document. It was the scope of a commercial agreement: the price was attached to it, and any change after signature went through a change management process, with an impact assessment and, often, a revised cost. Wiegers and Beatty describe this as the requirements baseline, the agreed set against which every later change is evaluated &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That document was far from perfect. Customers signed pages they had not fully understood, and the gap between what they read and what they later saw on screen was a constant source of change requests. Agile was partly a reaction to exactly this.&lt;/p&gt;

&lt;p&gt;Vibe coding has made much of that document feel unnecessary. For visible behaviour, a customer who can click through a working prototype understands what is being built far better than one who reads two hundred pages of “the system shall.” But a prototype does not by itself establish what has been agreed, what remains undecided, or what the system must do when things go wrong. It is a discovery tool, not a requirements baseline.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/requirement-not-reality/srs-prototype-baseline.svg&quot; alt=&quot;Comparison of a signed SRS, a prototype alone, and frozen decisions with a prototype as illustration, across shared understanding, baseline, exceptions, expectations and change management&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The signed document did at least two jobs the prototype does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was a baseline.&lt;/strong&gt; It said what had been agreed, so that a change could be recognised as a change. A prototype does not separate what was agreed from what the model happened to generate. When the customer later says “but it did this in the demo,” it is hard to say whether that behaviour was a decision or an accident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It covered what screens do not show.&lt;/strong&gt; A prototype shows the happy path beautifully. It is mostly silent on what happens when the switch times out, when a reversal arrives late, when a limit is breached, or how fast the system must respond under load. In payments, those are precisely the things that turn into disputes.&lt;/p&gt;

&lt;p&gt;And there is a third problem the old document never had. A customer who has clicked through something that looks finished tends to believe it nearly is. The prototype becomes the product in their mind, and sometimes in the plan, which is the failure from the previous section arriving through the commercial door rather than the technical one.&lt;/p&gt;

&lt;p&gt;All of this makes requirements much harder to freeze. When the next version is one prompt away, every meeting can produce a new idea, and without a baseline every change request becomes a negotiation.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;freezing-what-can-be-frozen&quot;&gt;Freezing what can be frozen&lt;/h2&gt;

&lt;p&gt;I do not think the answer is to go back to two-hundred-page specifications. I think it is to be selective about what we freeze.&lt;/p&gt;

&lt;p&gt;In &lt;em&gt;The Hollow Sprint&lt;/em&gt; I separated two kinds of decision &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. &lt;strong&gt;Regenerable&lt;/strong&gt; decisions, such as screen layouts, wording or the order of steps in a form, are cheap to reverse; being wrong means regenerating one piece. &lt;strong&gt;Load-bearing&lt;/strong&gt; decisions are the ones everything else comes to depend on: what counts as a completed transaction, how a reversal settles, what is written to the ledger, which limits and controls apply, what the integration contracts with the bank or switch look like, and the performance and security requirements the system must meet.&lt;/p&gt;

&lt;p&gt;That distinction suggests a different shape for the agreement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Freeze the load-bearing decisions.&lt;/strong&gt; Write them down precisely, have the customer confirm them, baseline them, and put them under change management. This is a much shorter document than the old SRS, but each line in it matters.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Let the regenerable decisions stay open.&lt;/strong&gt; Iterate on them with the customer using the prototype, which becomes an illustration of intent rather than the contract itself.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Apply change management where change is expensive.&lt;/strong&gt; A new screen layout should not need an impact assessment. A change to how reversals settle always should.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have not seen many contracts written this way yet, and I am not sure how pricing should work when part of the scope is deliberately left open. That feels like an unsolved problem for project companies in particular. One possibility I would like to explore is to fix the price and acceptance criteria for the load-bearing decisions, and treat the visible experience as iterative scope within an agreed time budget. The contract would then protect what must not change without pretending every screen is known in advance. I offer that as an idea, not as something I have seen proven. But it seems closer to the truth than either extreme: a signed document that pretends everything is known, or a prototype that pretends nothing needs to be.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-spec-driven-development-looks-like-today&quot;&gt;What spec-driven development looks like today&lt;/h2&gt;

&lt;p&gt;Those frozen, load-bearing decisions have to live somewhere, and spec-driven development is the obvious candidate. Before arguing about whether it is the answer, it is worth looking at what the term currently means in practice, because it is younger than it sounds. Most of the tooling appeared in the second half of 2025. Three tools come up most often, and Birgitta Böckeler’s hands-on review of them on martinfowler.com is the most careful comparison I have found &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Spec Kit&lt;/strong&gt; is an open-source, MIT-licensed toolkit that sets up a repository so that a coding agent works through a fixed sequence &lt;a href=&quot;#ref-14&quot;&gt;[14]&lt;/a&gt;. A project starts with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;constitution.md&lt;/code&gt; of principles that apply to every change. Each feature then moves through &lt;em&gt;specify&lt;/em&gt;, &lt;em&gt;plan&lt;/em&gt;, &lt;em&gt;tasks&lt;/em&gt; and &lt;em&gt;implement&lt;/em&gt;, producing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec.md&lt;/code&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plan.md&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks.md&lt;/code&gt;. The current documentation adds an &lt;em&gt;analyze&lt;/em&gt; step that reports gaps between those artifacts and a &lt;em&gt;converge&lt;/em&gt; step that checks the implementation against them. The philosophy is stated bluntly in the project’s methodology document: “Specifications don’t serve code—code serves specifications” &lt;a href=&quot;#ref-15&quot;&gt;[15]&lt;/a&gt;. The project began in August 2025 and reached version 1.0.0 in August 2026, by which point its documentation listed 38 coding-agent integrations &lt;a href=&quot;#ref-14&quot;&gt;[14]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kiro&lt;/strong&gt; is Amazon’s agentic development environment, built on VS Code and launched in July 2025 &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;. Its pitch was explicitly framed against vibe coding: to combine “the flow of vibe coding” with “the clarity of specs.” A Kiro spec is three files: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requirements.md&lt;/code&gt;, written as user stories with acceptance criteria in EARS notation (“WHEN [condition or event] THE SYSTEM SHALL [expected behaviour]”), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;design.md&lt;/code&gt; for architecture and sequence diagrams, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks.md&lt;/code&gt; for the implementation plan &lt;a href=&quot;#ref-17&quot;&gt;[17]&lt;/a&gt;. Alongside specs, Kiro has &lt;em&gt;steering&lt;/em&gt; files that describe the product, technology and structure, and &lt;em&gt;hooks&lt;/em&gt;, event-driven automations that run an agent when something changes, such as updating a test file when a component is saved &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tessl&lt;/strong&gt; is the most ambitious of the three and, when Böckeler reviewed it, still in private beta &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. Specifications live in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.spec.md&lt;/code&gt; files, each currently mapped to one code file, and the generated code carries a header comment telling people not to edit it: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;// GENERATED FROM SPEC - DO NOT EDIT&lt;/code&gt;. Of the three, it is the one that openly aims beyond the first release.&lt;/p&gt;

&lt;p&gt;Böckeler offers a useful way to place them. She distinguishes three levels of spec-driven development: &lt;em&gt;spec-first&lt;/em&gt;, where a specification guides the task in hand; &lt;em&gt;spec-anchored&lt;/em&gt;, where it is maintained as the feature evolves; and &lt;em&gt;spec-as-source&lt;/em&gt;, where people edit only the specification and never touch the generated code &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. Putting vibe coding at the start of the same scale makes something visible that the prose hides.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/requirement-not-reality/spec-levels.svg&quot; alt=&quot;Vibe coding and the three levels of spec-driven development, showing whether the spec stays true after release and whether a person reads the code, with Spec Kit, Kiro and Tessl placed as reviewed in October 2025&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Her experience with the tools in October 2025 was mixed, and I think her caveats matter as much as the features. Kiro turned a small bug into four user stories with sixteen acceptance criteria. Spec Kit generated many verbose markdown files that she found more tedious to review than code, and its agent sometimes ignored notes about existing classes and created duplicates. Regenerating code from the same Tessl spec produced different results each time. Her review predates Spec Kit 1.0, so some of this may have moved on; I take it as a snapshot of where the tools were, not a ranking of where they are.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-tool-not-the-discipline&quot;&gt;A tool, not the discipline&lt;/h2&gt;

&lt;p&gt;What strikes me most is not any individual feature but where the tools stop.&lt;/p&gt;

&lt;p&gt;A product does not just need a well-documented first release; it needs a specification that is still true at release ten. That is the spec-anchored level, and it is exactly the part the tools leave to people. Spec Kit’s own documentation is admirably honest about this. It now names Böckeler’s three levels itself, describes three ways a team might maintain its specs after delivery, and says plainly that none is the default: “The model is a team convention, not a CLI setting” &lt;a href=&quot;#ref-18&quot;&gt;[18]&lt;/a&gt;. In other words, the tool can carry a specification to the first release. Whether it stays true afterwards is still a matter of discipline.&lt;/p&gt;

&lt;p&gt;There is a subtler limit as well. A specification can make a wrong decision consistent and repeatable; it cannot make the decision right. If the reversal rule in the spec is wrong, the agent will implement it faithfully and the tests will confirm it faithfully. That still depends on domain knowledge and on the people with the authority to make the decision.&lt;/p&gt;

&lt;p&gt;Spec-as-source makes me pause for a different reason. It asks people never to touch, and in practice never to read, the generated code. Structurally, that is the same bet vibe coding makes. Böckeler raises a related worry: that it may combine the rigidity of model-driven development with the non-determinism of language models &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. A careful specification in front of the bet is much better than nothing, but it does not bring back the reader.&lt;/p&gt;

&lt;p&gt;And even a correct, current specification and well-understood code are not the whole story. Someone also has to be accountable once the system is live: for what happens when an assumption fails at month-end, when the bank changes its message format, or when reconciliation shows a difference nobody predicted. Understanding the code, owning the business rule and owning the system in production are three different responsibilities, and a healthy team knows who holds each.&lt;/p&gt;

&lt;p&gt;So I have ended up thinking of spec-driven development as a very useful tool for carrying the discipline, not as the discipline itself. Whatever a team chooses, the discipline still has to live somewhere: in someone who understands the specification, the code, and the gap between them.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-i-have-landed-for-now&quot;&gt;Where I have landed, for now&lt;/h2&gt;

&lt;p&gt;If I had to put my current view in a few sentences:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Software engineering began as an aspiration to stop things falling through the cracks, and most of its practices are nets that catch what one person misses.&lt;/li&gt;
  &lt;li&gt;Using AI to write code does not abandon that aspiration. Removing the accountable human reader does.&lt;/li&gt;
  &lt;li&gt;How much discipline a system needs depends on how long it lives and what its failure would cost; few systems are as short-lived as they first appear.&lt;/li&gt;
  &lt;li&gt;In fintech, the discipline is partly written into standards, which makes code that nobody read hard to defend.&lt;/li&gt;
  &lt;li&gt;Vibe coding belongs at the start, as a way of seeing requirements. What should survive it is the decisions, not the code.&lt;/li&gt;
  &lt;li&gt;For visible behaviour, a prototype builds shared understanding better than a prose SRS, but it is not a baseline. Freeze the load-bearing decisions; let the regenerable ones stay open.&lt;/li&gt;
  &lt;li&gt;Today’s spec-driven tools, such as Spec Kit, Kiro and Tessl, are good at carrying a specification to the first release. Keeping it true afterwards, and understanding the code beneath it, is still left to people.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Randell’s phrase has stayed with me since I first read it. Fifty-eight years on, software engineering is still in some ways a requirement rather than a reality. AI has made it far easier to produce software, and so it has also made it easier to forget the requirement. I do not think the answer is to produce less. I think it is to keep asking, for each piece of code, who has actually understood it.&lt;/p&gt;

&lt;p&gt;I may well be wrong about parts of this. If you have seen vibe-coded systems hold up well over years of change, or disciplined teams where the nets failed anyway, I would genuinely like to hear about it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;ref-1&quot;&gt;&lt;/a&gt;[1] Brian Randell, “Fifty Years of Software Engineering, or The View from Garmisch,” keynote at ICSE 2018 (May 2018). &lt;a href=&quot;https://arxiv.org/abs/1805.02742&quot;&gt;arXiv:1805.02742&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-2&quot;&gt;&lt;/a&gt;[2] Robert L. Glass, &lt;em&gt;Facts and Fallacies of Software Engineering&lt;/em&gt; (Addison-Wesley, 2002), Facts 41 and 44.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-3&quot;&gt;&lt;/a&gt;[3] M. M. Lehman, “Programs, Life Cycles, and Laws of Software Evolution,” &lt;em&gt;Proceedings of the IEEE&lt;/em&gt; 68, no. 9 (1980).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-4&quot;&gt;&lt;/a&gt;[4] Andrej Karpathy, post on X (2 February 2025). &lt;a href=&quot;https://x.com/karpathy/status/1886192184808149383&quot;&gt;x.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-5&quot;&gt;&lt;/a&gt;[5] Simon Willison, “Not all AI-assisted programming is vibe coding (but vibe coding rocks)” (19 March 2025). &lt;a href=&quot;https://simonwillison.net/2025/Mar/19/vibe-coding/&quot;&gt;simonwillison.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-6&quot;&gt;&lt;/a&gt;[6] Martin Fowler, “Vibe Coding,” martinfowler.com bliki. &lt;a href=&quot;https://martinfowler.com/bliki/VibeCoding.html&quot;&gt;martinfowler.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-7&quot;&gt;&lt;/a&gt;[7] Ali Ahmed Thawerani, “The Inevitable Cycles: Why Software Houses Keep Returning to Square One,” TECTONICS (January 2026). &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;aathawerani.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-8&quot;&gt;&lt;/a&gt;[8] Ali Ahmed Thawerani, “The Hollow Sprint,” TECTONICS (October 2026). &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;aathawerani.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-9&quot;&gt;&lt;/a&gt;[9] PCI Security Standards Council, &lt;em&gt;Payment Card Industry Data Security Standard: Requirements and Testing Procedures&lt;/em&gt;, version 4.0.1 (June 2024), Requirements 6.2.3 and 6.2.3.1. &lt;a href=&quot;https://www.pcisecuritystandards.org/document_library/&quot;&gt;PCI SSC Document Library&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-10&quot;&gt;&lt;/a&gt;[10] Karl Wiegers and Joy Beatty, &lt;em&gt;Software Requirements&lt;/em&gt;, 3rd ed. (Microsoft Press, 2013), chapters on prototyping and on requirements change management.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-11&quot;&gt;&lt;/a&gt;[11] Frederick P. Brooks Jr., &lt;em&gt;The Mythical Man-Month: Essays on Software Engineering&lt;/em&gt; (Addison-Wesley, 1975), chapter 11, “Plan to Throw One Away.”&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-12&quot;&gt;&lt;/a&gt;[12] Ali Ahmed Thawerani, “Tech Stack Selection in the Age of AI Agents,” TECTONICS (May 2026). &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;aathawerani.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-13&quot;&gt;&lt;/a&gt;[13] Birgitta Böckeler, “Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl,” martinfowler.com (15 October 2025). &lt;a href=&quot;https://www.martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html&quot;&gt;martinfowler.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-14&quot;&gt;&lt;/a&gt;[14] GitHub, &lt;em&gt;Spec Kit&lt;/em&gt; repository, README and project history (accessed October 2026). &lt;a href=&quot;https://github.com/github/spec-kit&quot;&gt;github.com/github/spec-kit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-15&quot;&gt;&lt;/a&gt;[15] GitHub, “Spec-Driven Development,” &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec-driven.md&lt;/code&gt; in the Spec Kit repository. &lt;a href=&quot;https://github.com/github/spec-kit/blob/main/spec-driven.md&quot;&gt;github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-16&quot;&gt;&lt;/a&gt;[16] SD Times, “Amazon launches spec-driven AI IDE, Kiro” (14 July 2025). &lt;a href=&quot;https://sdtimes.com/ai/amazon-launches-spec-driven-ai-ide-kiro/&quot;&gt;sdtimes.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-17&quot;&gt;&lt;/a&gt;[17] Kiro documentation, “Specs: concepts.” &lt;a href=&quot;https://kiro.dev/docs/specs/concepts&quot;&gt;kiro.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-18&quot;&gt;&lt;/a&gt;[18] GitHub, “Spec Persistence Models,” Spec Kit documentation (accessed October 2026). &lt;a href=&quot;https://github.com/github/spec-kit/blob/main/docs/concepts/spec-persistence.md&quot;&gt;github.com&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 29 Oct 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/</guid>
      </item>
    
      <item>
        <title>The Hollow Sprint</title>
        <description>&lt;p&gt;A team can now build in days what the business needs weeks to confirm. The sprint still ends on Friday, the demo still runs, and every signal says the work is done. Whether it is the &lt;em&gt;right&lt;/em&gt; work is a question the process no longer has time to answer.&lt;/p&gt;

&lt;p&gt;That is a new problem, and to see why, it helps to remember what Agile was for in the first place.&lt;/p&gt;

&lt;p&gt;Agile was an answer to a hard question: &lt;strong&gt;what do you do when you cannot know what to build until you have built some of it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer before Agile was to try harder at knowing. Barry Boehm’s work showed that a defect found late can cost far more to fix than the same defect found early &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;, so the rational response was to specify as much as possible before building. That is the logic of Waterfall, and it was not stupid. Its weakness was the assumption that enough upfront effort could produce certainty about what customers needed. It usually could not.&lt;/p&gt;

&lt;p&gt;Agile’s answer was different. Kent Beck argued that with test-driven development, continuous integration and refactoring, the cost of change could be flattened enough that deferring decisions stopped being reckless &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. Mary and Tom Poppendieck gave the idea its best name: make each decision at the &lt;em&gt;last responsible moment&lt;/em&gt; &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;. Plan a little, build a little, show it to the customer, learn, adjust.&lt;/p&gt;

&lt;p&gt;That answer was a trade-off between two costs. One was the &lt;strong&gt;cost of building&lt;/strong&gt;: every increment took real developer time, so you could not afford to build many versions of anything. The other was the &lt;strong&gt;cost of being wrong&lt;/strong&gt;: the further you went on a mistaken assumption, the more you had to throw away. Short iterations balanced the two. Build enough to learn something; not so much that being wrong is ruinous.&lt;/p&gt;

&lt;p&gt;AI has changed one side of that trade-off dramatically. Building is far cheaper than it was. The cost of being wrong has not moved in the same way. When one side of a balanced trade-off changes, the balance point moves. The question for anyone running software delivery is where it moves to, and whether our processes have noticed.&lt;/p&gt;

&lt;p&gt;My answer is that it moves in two directions at once. Before getting there, it is worth looking at what happens when a team does not notice at all.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-hollow-sprint&quot;&gt;The hollow sprint&lt;/h2&gt;

&lt;p&gt;When I learned Scrum, the purpose of a sprint was to produce a shippable outcome frequently. The 2017 Scrum Guide said exactly that: “the purpose of each Sprint is to deliver Increments of potentially releasable functionality.” &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt; The 2020 edition kept the idea, requiring the increment to be usable, and added a second purpose that is easy to miss: “Shorter Sprints can be employed to generate more learning cycles and limit risk of cost and effort to a smaller time frame.” &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the sprint has two jobs. It turns ideas into usable value, and it &lt;strong&gt;limits risk&lt;/strong&gt; by capping how much gets built before the next chance to learn whether it was the right thing. For twenty years these jobs moved together. Two weeks of human effort produced an increment small enough for a review to absorb. Don Reinertsen’s work on product development flow explains why that size mattered: the more work built between two feedback points, the more assumptions ride on each one, and the more rework a wrong assumption causes &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AI separates the two jobs. The first gets easier: usable increments arrive faster than ever. The second quietly fails, because the time-box only limited risk while human output limited the batch. Put another way, the sprint used to control two capacities at once: how much the team could build, and how many decisions the business could absorb. As long as the first was the smaller of the two, controlling it controlled both. &lt;strong&gt;AI has made build capacity and decision capacity diverge.&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/hollow-sprint/timebox-batch.svg&quot; alt=&quot;Same two-week time-box containing a small batch of unvalidated change in the past and a much larger batch with AI-assisted development&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;I call the result &lt;strong&gt;the hollow sprint&lt;/strong&gt;: a sprint that still delivers a usable increment on schedule, with every ceremony intact, while the amount of unconfirmed work inside it has grown beyond what one feedback point can check.&lt;/p&gt;

&lt;p&gt;What makes it dangerous is that it reports success. The Scrum Guide never defines a failed sprint. The Sprint Goal is set by the team, the Definition of Done is a quality standard the team holds itself to, and the guide is explicit that “the Sprint Review should never be considered a gate to releasing value.” &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt; None of that was a flaw when building was slow, because the customer saw everything soon anyway. With AI, generated code meets the Sprint Goal, passes the tests and satisfies Done. Every official signal says the sprint went well. Nobody outside the team has confirmed anything.&lt;/p&gt;

&lt;p&gt;I argued in &lt;a href=&quot;/systems/culture/scale/2026/08/02/the-evaluation-constraint/&quot;&gt;The Evaluation Constraint&lt;/a&gt; that AI made trying things cheap and left knowing whether they worked expensive, and in &lt;a href=&quot;/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt; that it can produce software faster than a team can understand it. The hollow sprint is what that looks like inside a delivery process: the knowing falls behind, and the process has no alarm that rings when it does.&lt;/p&gt;

&lt;p&gt;One caution. The throughput gain is not universal. A 2025 randomized trial by METR found experienced developers working in mature codebases they knew well were &lt;em&gt;slower&lt;/em&gt; with AI tools, even though they believed they were faster &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;. Integration-heavy, regulated systems, the kind I work on, are where gains are smallest. The argument does not need AI to make everyone faster. It needs only this: &lt;strong&gt;wherever throughput has jumped, the time-box has stopped limiting risk.&lt;/strong&gt; You can check that in your own team by comparing how much changed between your last two sprint reviews with the same comparison two years ago.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-fork&quot;&gt;The fork&lt;/h2&gt;

&lt;p&gt;So the old balance is broken. Where does the new one sit? There are two credible answers, and they point in opposite directions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario A: plan more.&lt;/strong&gt; If implementation is cheap, the time spent defining requirements no longer competes so directly with building. Three days sharpening a specification used to cost three days of development; now it costs a small fraction of what it would take to generate, integrate and unwind the wrong system. Meanwhile, every wrong assumption gets built on faster, by agents that do not stop to ask. On this reading, the economically rational move is toward more upfront definition: settle requirements, interfaces and constraints before generating anything large. Practitioners already have a name for the shape this produces. In 2011 Dave West of Forrester called it &lt;em&gt;Water-Scrum-Fall&lt;/em&gt;: upfront planning and downstream release gates wrapped around a Scrum middle &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. It was meant as a criticism. AI makes it look like a rational design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario B: iterate more.&lt;/strong&gt; If implementation is cheap, so is a prototype. A team can show a customer three working versions of a workflow in the time it once took to write one requirements document. Why spend days specifying what the customer wants when you can generate something and watch them react to it? If prototypes become nearly free, iteration itself becomes cheaper, and the rational move is to build more and earlier, and plan less.&lt;/p&gt;

&lt;p&gt;Both arguments are sound, and both have evidence on their side. Scenario A matches what happens when teams generate large amounts of code on a misunderstood requirement. Scenario B matches what happens when product teams use prototypes to settle questions in an afternoon that used to take a sprint.&lt;/p&gt;

&lt;p&gt;They cannot both be the right default. But they can both be right.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;it-depends-on-the-decision&quot;&gt;It depends on the decision&lt;/h2&gt;

&lt;p&gt;The fork dissolves once you stop asking it about the project as a whole and ask it about each decision inside the project. The missing variable is not the size of the project or the maturity of the team. It is one property of each decision: &lt;strong&gt;what happens when you reverse it.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;A regenerable decision is one whose reversal is contained. A load-bearing decision is one whose reversal invalidates the decisions built on top of it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Regenerable decisions&lt;/strong&gt; include screen layouts, the order of steps in a form, wording, dashboards, internal module structure, an implementation choice behind a stable interface. Being wrong means regenerating one piece. For these, Scenario B is usually the better default: build, show, learn, regenerate. Their last responsible moment moves &lt;em&gt;later&lt;/em&gt; than Agile ever allowed, because changing them is now almost free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Load-bearing decisions&lt;/strong&gt; are the ones everything else comes to depend on. In payments they are easy to name: what counts as a completed transaction; what happens when the switch times out after a debit has posted; how a late reversal settles; what is written to the ledger before a notification is sent; which regulatory controls apply. For these, Scenario A is usually the better default. Their last responsible moment moves &lt;em&gt;earlier&lt;/em&gt;, to before the generation that depends on them, because AI builds on top of them so quickly.&lt;/p&gt;

&lt;p&gt;A small example shows the difference. Suppose an agent builds a wallet’s reversal flow on the assumption that a timeout means the original debit failed. The screen that tells the customer “your payment did not go through” can be regenerated in minutes. But if the same assumption has already shaped the ledger entries, the reconciliation job, the notification logic and the settlement file, then correcting it is not a small change. The bank may in fact have completed the debit, and every component built on the opposite premise now disagrees with the bank. The code may be cheap to rewrite. &lt;strong&gt;The decision graph is not.&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/hollow-sprint/last-responsible-moment-split.svg&quot; alt=&quot;AI moves the last responsible moment earlier for load-bearing decisions and later for regenerable decisions&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This is the core of the argument. &lt;strong&gt;AI did not settle the debate between planning and iterating. It split it in two.&lt;/strong&gt; The single “last responsible moment” that Agile applied to every decision has become two moments moving in opposite directions. A team that keeps one rhythm for everything gets both wrong: it over-plans the regenerable work, wasting the cheapest thing it has, and under-plans the load-bearing work, letting agents build fast on premises nobody has confirmed. AI scales up whatever the team misunderstands between feedback points, and it does so most expensively on the decisions that carry weight.&lt;/p&gt;

&lt;p&gt;The two-line version is something a team can carry into its next planning session:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Contained reversal: defer and iterate.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cascading reversal: decide earlier.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice this is a spectrum rather than two clean boxes, and where a decision falls is itself a judgment call that can be wrong. A UI choice becomes load-bearing once an integration partner depends on it; a ledger detail can be contained if it sits behind a well-defined interface. Even so, “what happens if we reverse this?” is a far more useful question than “Agile or Waterfall?”, because it can be asked about each decision on its own, today, by people who know the domain.&lt;/p&gt;

&lt;h3 id=&quot;decide-earlier-does-not-mean-specify-upfront&quot;&gt;Decide earlier does not mean specify upfront&lt;/h3&gt;

&lt;p&gt;There is an obvious objection here: isn’t “decide load-bearing decisions earlier” just Waterfall for the important parts? It would be, if deciding earlier meant writing a long requirements document. It does not have to.&lt;/p&gt;

&lt;p&gt;Reversal cost tells you &lt;em&gt;when&lt;/em&gt; a decision must be settled. Two other questions tell you &lt;em&gt;how&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;How uncertain is the decision?&lt;/strong&gt; Some load-bearing decisions are well understood. Whether transaction state is authoritative in the wallet service or in the payment switch is consequential, but an experienced team can usually settle it in a design conversation and record it. Others are genuinely open. Whether to support one settlement model or three is just as load-bearing, but nobody knows the answer from a meeting room.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;How cheaply can the uncertainty be resolved?&lt;/strong&gt; For the open questions, the right response is rarely a three-week requirements phase. It is often a few thin, throwaway models or prototypes, built in days, shown to the people who know the business, and discarded once the decision is made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the full rule has three parts: reversal cost sets the deadline, uncertainty sets the effort, and the cheapest way to resolve that uncertainty sets the method. Important, uncertain decisions get resolved deliberately &lt;em&gt;before&lt;/em&gt; downstream generation, and that resolution can itself be thoroughly iterative. What changes is not whether a team iterates, but what it iterates on: the decision first, then the system built on it.&lt;/p&gt;

&lt;p&gt;It also explains why neither camp’s evidence is wrong. The teams who say AI makes them more Agile are mostly prototyping regenerable things. The teams who find themselves drifting toward upfront specification are mostly building systems where the expensive decisions are load-bearing. Fintech, healthcare and anything regulated sits heavily in the second group.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-this-does-to-agiles-commitments&quot;&gt;What this does to Agile’s commitments&lt;/h2&gt;

&lt;p&gt;Agile’s manifesto is short, and only part of it speaks to the balance between planning and iterating &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;. Two of its values change in specific ways once decisions are split.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Responding to change over following a plan”&lt;/strong&gt; is stronger than ever for regenerable decisions, where change is nearly free. For load-bearing decisions something subtler happens. The fastest way to change a generated system is no longer to edit its code but to edit its specification and regenerate. Responding to change increasingly &lt;em&gt;means&lt;/em&gt; changing the plan; the plan stops being what change fights against and becomes the medium change travels through. &lt;strong&gt;“Working software over comprehensive documentation”&lt;/strong&gt; shifts in the same way. The rejection of documents written to satisfy process still holds, but a precise statement of load-bearing rules is no longer a description of software someone will write later. It is the input software is generated from. I wrote about the engineering side of this in &lt;a href=&quot;/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;; the same shift applies to business rules.&lt;/p&gt;

&lt;p&gt;The principles behind the manifesto follow the same split &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;. Welcoming late changes, letting designs emerge, and treating working software as the measure of progress all remain sound for regenerable decisions. For load-bearing ones they need a qualifier: late change means unwinding generated work, emergent design means inheriting whatever each generation step assumed, and running software proves little when it can run perfectly while encoding the wrong settlement model. None of this makes the manifesto obsolete. It treated every decision as one class, because at human pace there was no reason not to.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-customer-side&quot;&gt;The customer side&lt;/h2&gt;

&lt;p&gt;If load-bearing decisions have to be confirmed before generation, someone has to confirm them. In most organizations that is the part of the system with the least spare capacity: the customer, the product owner, the domain expert, the compliance reviewer. Making Agile work in the AI era is mostly about this side of the table, and it is the part engineering leaders most often leave to chance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know your validation capacity.&lt;/strong&gt; Every organization has a finite number of customers, product owners, domain experts and compliance reviewers able to confirm load-bearing decisions carefully. AI can multiply generation capacity far faster than it can multiply those people. Little’s Law, one of the sturdiest results in operations research, says that in a stable system the number of items waiting equals their arrival rate multiplied by how long each waits &lt;a href=&quot;#ref-11&quot;&gt;[11]&lt;/a&gt;. If agents produce load-bearing decisions faster than they are confirmed, the queue grows and so does the wait. Faster generation does not shorten that wait; it lengthens it. So plan against validation capacity, not against the team’s build capacity and not against the calendar: unconfirmed load-bearing decisions in flight should not exceed what the business can confirm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wire customer confirmation into the stop signal.&lt;/strong&gt; The hollow sprint survives because every signal that ends a cycle is judged by the team. Each method has a place to change that without abandoning the method. In Scrum, state the Sprint Goal as a confirmed outcome rather than an output, and add a line to the Definition of Done: every load-bearing decision in this increment has been confirmed by the Product Owner or customer. In Kanban, which has no sprints but limits work in progress &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;, add an explicit “awaiting confirmation” stage with its limit set to the business’s validation capacity, and keep items small enough that each carries only one or two load-bearing decisions. In XP, keep customer-owned acceptance tests as the definition of done, and keep the agents from writing the tests they are checked against.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run a daily decision loop.&lt;/strong&gt; Instruct agents to record the assumptions they make, not only the code they write. Each day, developers sort the log: regenerable assumptions they decide themselves; load-bearing ones go to a business representative in a short, fixed slot, and the answers go back into the specification so the same question is never asked twice. This is XP’s On-Site Customer, given a sharper job &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. It also carries XP’s warning: when Angela Martin, Robert Biddle and James Noble studied the customer role on real projects, they found it so demanding that representatives were overloaded and the role was hard to sustain &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. Agents ask more questions than developers did. The loop works only if the representative has the authority to decide without escalating, protected time that is part of the job rather than on top of it, and a triage step that shows them only load-bearing questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spend prototypes where uncertainty is high.&lt;/strong&gt; As the rule above implies, Scenario B is right for regenerable decisions, and it is also often the best way to resolve an uncertain load-bearing one: a new workflow, a pricing or settlement model, an onboarding journey. Have the product manager build the visible part with the customer in the room, keep the confirmed decisions, and throw the prototype away. But every prototype spends customer attention, so it draws on the same validation capacity.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/hollow-sprint/validation-bounded-delivery.svg&quot; alt=&quot;Delivery loop: intent, classify decisions, confirm load-bearing decisions with the customer, generate, verify, with an assumption log feeding a daily triage that updates the specification&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Measure the constraint that matters.&lt;/strong&gt; Velocity and story points measure building capacity. In AI-assisted teams where that capacity has expanded sharply, it may no longer be the constraint that matters most. The most important measure is &lt;strong&gt;decision latency&lt;/strong&gt;: the time from an assumption being logged to it being confirmed or corrected by someone with business authority. If it is rising while the ceremonies stay the same, the process is no longer agile in any meaningful sense, whatever it is called. Two more measures support it: &lt;strong&gt;unconfirmed load-bearing decisions in flight&lt;/strong&gt;, which should stay within validation capacity; and &lt;strong&gt;rework from overturned assumptions&lt;/strong&gt;, the generated work thrown away because an unconfirmed premise turned out wrong. That last one is the direct cost of a hollow sprint, and it usually goes unseen because regeneration makes it feel cheap.&lt;/p&gt;

&lt;p&gt;None of these practices is new. Customer acceptance tests, on-site customers, work-in-progress limits and queueing theory all predate this wave of AI. What is new is the reason to take them seriously. For twenty years they were optional, because slow building did their job for free.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-decision-is-the-unit&quot;&gt;The decision is the unit&lt;/h2&gt;

&lt;p&gt;So is Waterfall coming back? Not as a methodology. What is going away is the idea that a whole project needs a single delivery philosophy.&lt;/p&gt;

&lt;p&gt;A single payments project can now contain Waterfall-like treatment for transaction semantics, ledger behaviour, settlement, data ownership, security boundaries and regulatory rules, and thoroughly Agile treatment for screens, workflows, copy, dashboards and internal implementation, all at the same time. The question “are we an Agile shop or a Waterfall shop?” stops being useful. &lt;strong&gt;The unit of methodology is no longer the project or the feature. It is the decision.&lt;/strong&gt; The answer to the hollow sprint is not to return to Waterfall. It is to stop treating every decision as if it had the same reversal economics.&lt;/p&gt;

&lt;p&gt;That also changes what a CTO should watch. When AI raises build throughput, the constraint moves to the next thing in line, and in most organizations that is the rate at which the business can confirm the decisions embedded in the work. Decision latency is the measure of that constraint, which makes it, not velocity, the number that tells you whether your delivery process is keeping up.&lt;/p&gt;

&lt;p&gt;I should be clear about what this post is. It is an argument, not a measured result. I have not seen the daily decision loop or these measures tested at scale, and the measures above are how you would find out whether they work in your organization. The real cost also falls where engineering leaders have least control: on the business side, which has to give daily, protected time to confirming decisions. If an organization cannot provide that, the honest fallback is the unpopular one: deliberately build less per cycle than the team is capable of, so the batch stays within what the customer can absorb.&lt;/p&gt;

&lt;p&gt;For a CTO, the questions are short:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which decisions in your current roadmap are load-bearing, and have they been confirmed by someone with business authority?&lt;/li&gt;
  &lt;li&gt;When your process says the work is done, who decided that: the team, or the customer?&lt;/li&gt;
  &lt;li&gt;How long does a load-bearing decision wait before it is confirmed, and is that wait growing?&lt;/li&gt;
  &lt;li&gt;Are your sprint boundaries still controlling risk, or only the calendar?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agile taught us to delay each decision until the last responsible moment. AI has not made that principle obsolete. It has made us ask, for every decision, when that moment actually is.&lt;/p&gt;

&lt;p&gt;The future of software delivery may not be Agile or Waterfall. It may be knowing which decisions deserve each.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;ref-1&quot;&gt;&lt;/a&gt;[1] Barry W. Boehm, &lt;em&gt;Software Engineering Economics&lt;/em&gt; (Prentice Hall, 1981).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-2&quot;&gt;&lt;/a&gt;[2] Kent Beck, &lt;em&gt;Extreme Programming Explained: Embrace Change&lt;/em&gt; (Addison-Wesley, 1999).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-3&quot;&gt;&lt;/a&gt;[3] Mary Poppendieck and Tom Poppendieck, &lt;em&gt;Lean Software Development: An Agile Toolkit&lt;/em&gt; (Addison-Wesley, 2003).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-4&quot;&gt;&lt;/a&gt;[4] Ken Schwaber and Jeff Sutherland, &lt;em&gt;The Scrum Guide&lt;/em&gt; (November 2017), section on the Sprint.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-5&quot;&gt;&lt;/a&gt;[5] Ken Schwaber and Jeff Sutherland, &lt;em&gt;The Scrum Guide&lt;/em&gt; (November 2020), sections on the Sprint, Sprint Goal, Sprint Review and Definition of Done. &lt;a href=&quot;https://scrumguides.org/scrum-guide.html&quot;&gt;scrumguides.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-6&quot;&gt;&lt;/a&gt;[6] Donald G. Reinertsen, &lt;em&gt;The Principles of Product Development Flow: Second Generation Lean Product Development&lt;/em&gt; (Celeritas, 2009).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-7&quot;&gt;&lt;/a&gt;[7] METR, “Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity” (July 2025). &lt;a href=&quot;https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/&quot;&gt;metr.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-8&quot;&gt;&lt;/a&gt;[8] Dave West, “Water-Scrum-Fall Is The Reality Of Agile For Most Organizations Today,” Forrester Research (2011).&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-9&quot;&gt;&lt;/a&gt;[9] Kent Beck et al., &lt;em&gt;Manifesto for Agile Software Development&lt;/em&gt; (2001). &lt;a href=&quot;https://agilemanifesto.org/&quot;&gt;agilemanifesto.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-10&quot;&gt;&lt;/a&gt;[10] Kent Beck et al., &lt;em&gt;Principles behind the Agile Manifesto&lt;/em&gt; (2001). &lt;a href=&quot;https://agilemanifesto.org/principles.html&quot;&gt;agilemanifesto.org/principles.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-11&quot;&gt;&lt;/a&gt;[11] John D. C. Little, “A Proof for the Queuing Formula: L = λW,” &lt;em&gt;Operations Research&lt;/em&gt; 9, no. 3 (1961): 383–387.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-12&quot;&gt;&lt;/a&gt;[12] &lt;em&gt;The Kanban Guide&lt;/em&gt;, sections on WIP and flow. &lt;a href=&quot;https://kanbanguides.org/english/&quot;&gt;kanbanguides.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-13&quot;&gt;&lt;/a&gt;[13] Angela Martin, Robert Biddle and James Noble, “The XP Customer Role in Practice: Three Studies,” &lt;em&gt;Proceedings of the Agile Development Conference&lt;/em&gt; (2004).&lt;/p&gt;
</description>
        <pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/10/09/the-hollow-sprint/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/10/09/the-hollow-sprint/</guid>
      </item>
    
      <item>
        <title>The Evaluation Constraint</title>
        <description>&lt;h2 id=&quot;the-same-inputs-different-companies&quot;&gt;The Same Inputs, Different Companies&lt;/h2&gt;

&lt;p&gt;Take an engineering organization of sixty people: a couple of hundred services in production, an on-call rotation, a platform team, a primary framework two major versions behind, a data migration deferred twice, and a compliance deadline eleven months out. Decide how the sixty are distributed across all of it.&lt;/p&gt;

&lt;p&gt;Now take a second organization with the same sixty people, the same budget, the same stack, the same market and the same backlog. Give it a different distribution.&lt;/p&gt;

&lt;p&gt;Five years later these are not two versions of the same company. One has a platform that makes each new service cheaper than the last; the other has forty services that each cost full price to build and full price to keep alive. One absorbs a regulatory change in a quarter; the other discovers the change requires touching systems nobody fully understands, and spends three quarters finding out what they do. The gap did not come from talent, effort or process discipline. Both organizations worked hard and shipped continuously. The gap came from which allocation they found.&lt;/p&gt;

&lt;p&gt;This is what strategy literature means by &lt;strong&gt;superior allocation&lt;/strong&gt; — the observation that among the many ways an organization can distribute scarce resources, only a small number produce materially better long-run outcomes, and that finding one of those is the actual source of advantage rather than working harder inside whichever one you happen to have inherited.&lt;/p&gt;

&lt;p&gt;The effect size is not subtle. McKinsey’s long-running study tracked roughly 1,500 companies over two decades and found firms in the top third by reallocation activity delivered around 10 percent in average annual shareholder returns against roughly 6 percent for the bottom third — compounding to a company worth about twice as much within twenty years &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;. The distribution behind that number is the part worth sitting with: a third of those companies moved about one percent of their capital between businesses year over year. Most large organizations re-approve last year’s allocation with minor adjustments, for decades.&lt;/p&gt;

&lt;p&gt;That is not allocation. It is ratification.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Superior allocations exist and are rare. Almost every organization is operating in one it never chose, arrived at by accumulated default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The argument below runs in one line, and it is worth seeing whole before it is taken apart.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/causal-chain.svg&quot; alt=&quot;Scarcity leads to search, which decomposes into generation and evaluation, producing superior allocation, future capability and advantage&quot; /&gt;
&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;your-strategy-is-where-your-engineers-actually-are&quot;&gt;Your Strategy Is Where Your Engineers Actually Are&lt;/h2&gt;

&lt;p&gt;Before going further it is worth dispatching a comfortable belief: that allocation is downstream of strategy — leadership decides direction, engineering executes, and capacity distribution is the plumbing in between.&lt;/p&gt;

&lt;p&gt;Joseph Bower’s research at Harvard, beginning in 1970 and extended for three decades by Robert Burgelman, Clark Gilbert and Clayton Christensen, found close to the opposite &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. A company’s realized strategy emerges far less from formal statements of corporate strategy than from the accumulated pattern of resource commitments made across every level of the firm. Strategy is not decided and then allocated. Strategy is what the allocations turn out to have been.&lt;/p&gt;

&lt;p&gt;The clearest software demonstration is AWS. In 2003 two Amazon infrastructure engineers, Benjamin Black and Chris Pinkham, wrote a short paper describing infrastructure that was completely standardized, completely automated, and relied extensively on web services &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;. Bezos approved an experiment; Pinkham relocated to Cape Town and built EC2 there, deliberately away from Seattle. Amazon’s stated strategy was retail. The engineering capacity went to infrastructure anyway, and the strategy amended itself afterwards.&lt;/p&gt;

&lt;p&gt;Two details matter more than the story’s familiarity. The version most people know is false — the claim that AWS came from renting out spare retail capacity has been denied by Black himself, who says every part was purpose-built. And it was not a lone bottom-up insight either: Andy Jassy was concurrently writing a vision document for the same business, presented to the executive team that September and approved for 57 hires. Two allocation processes ran at once, from opposite ends of the organization, and the strategy followed both.&lt;/p&gt;

&lt;p&gt;For a CTO this is an uncomfortable diagnostic, and I include myself in it. Your technology strategy is not the deck you presented to the board. It is the sum of where your engineers spent last quarter. When the two disagree, the deck is the fiction — and it is usually the fiction being reported upward.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-makes-one-allocation-superior&quot;&gt;What Makes One Allocation Superior&lt;/h2&gt;

&lt;p&gt;If allocations differ so much in outcome, it is worth being precise about what actually varies between them, because the answer explains why judging them is hard.&lt;/p&gt;

&lt;p&gt;Two allocations can produce nearly identical output this quarter and leave the organization in completely different positions in three years. The difference is not in what gets shipped. It is in what each allocation does to the organization’s &lt;strong&gt;future capability&lt;/strong&gt; — its capacity to do the next thing, and the thing after that.&lt;/p&gt;

&lt;p&gt;Platform investment increases future capability; each subsequent service costs less than the last. Technical debt consumes it; every deferred decision raises the price of the ones that follow. Architecture shapes it by fixing which future changes are cheap and which are structurally expensive, and knowledge concentration constrains it by tying the organization’s ability to act to specific people.&lt;/p&gt;

&lt;p&gt;This is why superior allocation is genuinely difficult rather than merely uncommon. The variable that distinguishes a good allocation from a mediocre one is not visible in this quarter’s output. It sits in the future, in a counterfactual, in the cost of work that has not been attempted yet. Any organization can measure what it shipped. Almost none can measure what its choices did to what it will be able to ship.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-governance-doesnt-find-superior-allocations&quot;&gt;Why Governance Doesn’t Find Superior Allocations&lt;/h2&gt;

&lt;p&gt;If superior allocations are rare and valuable, the obvious question is how an organization finds one. The obvious answer — better process at the point of decision — is where most organizations have invested, and it does not work, for reasons that are structural rather than a matter of execution quality.&lt;/p&gt;

&lt;p&gt;For sixty engineers across even a handful of investment categories, the number of possible distributions is combinatorially enormous, and the number that are genuinely superior is vanishingly small by comparison. Finding one is therefore a &lt;strong&gt;search problem&lt;/strong&gt;: it requires visiting many points in that space and being able to tell them apart.&lt;/p&gt;

&lt;p&gt;Herbert Simon described the consequence sixty years before anyone was allocating engineering capacity &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;. Real decision-makers cannot evaluate all available alternatives, so they do not optimize — they &lt;em&gt;satisfice&lt;/em&gt;, generating options until one clears an acceptability threshold, then stopping. Bounded rationality is not a criticism of managers; it is a description of what is physically possible. Which means the question is never whether an organization searches exhaustively, because none does. It is how much of the space it covers before its threshold is met, and how good that threshold is.&lt;/p&gt;

&lt;p&gt;Now look at what the standard apparatus actually does. Investment committees, architecture review boards, portfolio dashboards, quarterly planning, OKRs — these are &lt;em&gt;decision procedures&lt;/em&gt;. A decision procedure evaluates the candidates that arrive in the room. It has no mechanism whatsoever for generating the candidate nobody proposed. An organization can run an immaculate governance process, with the right thresholds and the right cadence and genuinely capable people, and spend a decade choosing among three options in a space containing thousands — never discovering that the superior allocation was one that was never tabled.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Governance improves the quality of evaluation. It does not search the solution space. Those are different jobs, and in most organizations only one of them has been staffed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The default state is worse than this suggests. Peter Weill and Richard Woodham’s research on IT governance found that organizations tend to fall into recognisable archetypes — a monarchy where a small executive group decides everything, a feudal model where each unit decides independently, a federal blend of the two, or an anarchy in which decision rights were simply never assigned &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;. The uncomfortable finding is that anarchy is the most common state, not because anyone selected it but because it is what happens in the absence of a deliberate choice. Organizations are ungoverned by omission in exactly the way they are allocated by default. Both are the same failure: a structure nobody chose, inherited rather than searched for.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/allocation-search-space.svg&quot; alt=&quot;The allocation search space: many possible allocations, a small region of superior ones, and the narrow band most organizations explore&quot; /&gt;
&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;two-generators&quot;&gt;Two Generators&lt;/h2&gt;

&lt;p&gt;Search decomposes into generating candidates and evaluating them. The generation half is better understood than most engineering leaders realise, because Burgelman named its two modes decades ago &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;induced&lt;/strong&gt; process generates candidates that fit the current strategy. It runs top-down — leadership articulates a direction and the organization produces options consistent with it — and it is what people mean when they say a CEO’s mindset trickles down. It reduces variation and exploits what the organization already knows.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;autonomous&lt;/strong&gt; process generates candidates outside the current strategy, from people close enough to the frontline to notice a gap between the stated strategy and what the environment is doing. Black and Pinkham writing an infrastructure paper at a retailer is this. So is Amazon opening its storefront to third-party sellers, including direct competitors, which was contested internally and is now a majority of units sold.&lt;/p&gt;

&lt;p&gt;Burgelman’s finding is the useful part: successful organizations run both at once, and strategic reorientations are usually preceded by experimentation and selection through the autonomous process. With only the induced process an organization searches a narrow band around where it already is; with only the autonomous one it generates variety it cannot integrate.&lt;/p&gt;

&lt;p&gt;This also names the executive’s actual job in a way most job descriptions do not. Burgelman calls it &lt;em&gt;strategic context determination&lt;/em&gt;: evaluating the adaptive potential of autonomous initiatives and amending corporate strategy only once one has proven reasonably viable. That is not deciding. It is evaluating — which is a different skill, and, as the next section argues, the one that has recently become scarce.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-arm-that-used-to-be-expensive&quot;&gt;The Arm That Used to Be Expensive&lt;/h2&gt;

&lt;p&gt;Search has two arms and they are not symmetric in difficulty. Which one binds has changed, and almost every mechanism organizations currently rely on was built for the old answer.&lt;/p&gt;

&lt;p&gt;For most of the history of software, generation was the expensive arm. Producing a serious candidate — a working prototype, a migration actually attempted, an architecture built far enough to judge — cost months. Evaluation was nearly free by comparison: by the time you had built the thing you understood it, because building it was how you came to understand it. Understanding arrived as a by-product of construction.&lt;/p&gt;

&lt;p&gt;Look at what the industry built under that assumption. Reusable components, frameworks, package ecosystems, low-code platforms, and eventually code generation — a whole discipline aimed at making candidates cheaper to produce. The evaluation apparatus stayed thin because it did not need to be thick: code review, some architecture review, and the tacit judgment of whoever had built the last three systems.&lt;/p&gt;

&lt;p&gt;AI inverted the ratio. Generation is cheap and getting cheaper. Evaluation costs what it always did, because understanding no longer arrives as a by-product of construction — the construction happens without it. What remains is an apparatus optimised for the arm that stopped being scarce.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Search consists of generation and evaluation. Generation used to be the binding constraint. It no longer is, and the mechanisms built for it have not been replaced.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want to be careful with the primacy claim, because there are other plausible candidates for what limits allocation. Incentives determine which candidates get proposed. Politics determines which survive contact with the people whose budgets are affected. Information matters too. Each genuinely constrains allocation and I am not arguing otherwise.&lt;/p&gt;

&lt;p&gt;The test I would apply is what happens when you relax the others. Fix the incentives and you get a wider candidate set you still cannot judge. Remove the political friction and decisions move faster in directions nobody has verified. Add information and you have fed a process whose bottleneck is downstream. Raise evaluation capacity, though, and the others become legible: an organization that can judge options can see that its candidate set is skewed, and can tell which objections are analysis and which are territory. Incentives shape what appears, politics shapes what survives, information feeds the judgment — and evaluation is the step none of them substitute for.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-evaluation-capacity-comes-from&quot;&gt;Where Evaluation Capacity Comes From&lt;/h2&gt;

&lt;p&gt;The evaluation half has no equivalent vocabulary, which is part of why it goes unmanaged. It deserves a name, because everything below depends on it:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Evaluation capacity&lt;/strong&gt; is an organization’s ability to judge options it has not taken. It is the scarce input that determines whether allocation is search or ratification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stated that way the supply problem becomes tractable, because judgment about an option you have not taken cannot come from the option itself. It has not happened. It has to come from somewhere else, and as far as I can tell there are only four somewhere-elses: take a small piece of the option cheaply, have taken something like it before, find someone who took it and said what happened, or borrow judgment from someone who already has it. Buy it, remember it, borrow it, distribute it. Each buys a different kind of certainty at a different price.&lt;/p&gt;

&lt;p&gt;Buying it is what an &lt;strong&gt;experiment&lt;/strong&gt; does. The spike, the pilot, the limited rollout, the prototype whose purpose is information rather than delivery — each converts an unknown into evidence at a fraction of the cost of committing. It is the only source that produces evidence about &lt;em&gt;this&lt;/em&gt; option in &lt;em&gt;this&lt;/em&gt; system, which makes it the most precise of the four and, in most engineering organizations, the most underused, because work that produces a decision rather than a feature is hard to defend in a delivery-focused planning meeting.&lt;/p&gt;

&lt;p&gt;Remembering it is what &lt;strong&gt;experience&lt;/strong&gt; does, and it is really an experiment already paid for. An engineer who has been on the wrong end of a migration is carrying evidence about the next one that nobody has to purchase again. That makes experience the cheapest source at the point of use and the most expensive to acquire — and the most fragile, because it lives in people, is rarely written down, and leaves when they do. An organization whose judgment about architectural trade-offs sits in four heads has a search capability that two resignations can halve. Knowledge concentration is not a staffing inconvenience; it is a direct constraint on how many options the organization can consider.&lt;/p&gt;

&lt;p&gt;Borrowing it is what &lt;strong&gt;external evidence&lt;/strong&gt; does — the counterfactual someone else ran and published. When Amazon Prime Video’s monitoring team documented moving from distributed serverless components back to a monolith and reported roughly a ninety percent reduction in operating cost, every organization that read it acquired an evaluation input it never had to pay to generate &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;. The industry’s habit of publishing architectural post-mortems is, in aggregate, a shared evaluation commons, and it is why this source has grown faster than the other three. It is also the least transferable, for reasons the later discussion of open-loop decisions returns to.&lt;/p&gt;

&lt;p&gt;Distributing it is what &lt;strong&gt;shared priors&lt;/strong&gt; do, and this is the only source that scales without adding people. When leadership’s reasoning about trade-offs is legible enough that engineers three levels down apply it unaided — Netflix’s formulation is context, not control — the organization has spread its judgment rather than centralised its approvals, and can therefore evaluate in many places at once. This is what makes autonomy work when it works. It is not a values statement; it is a transmission mechanism, and an organization that cannot articulate its own reasoning has nothing to transmit.&lt;/p&gt;

&lt;p&gt;Notice what the four have in common: none of them is a decision process. They are all ways of acquiring evidence about a road not taken. Which is why an organization can improve its governance indefinitely and not become better at allocation — it is refining how it chooses between candidates while doing nothing about how well it can tell them apart.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/two-generators-four-sources.svg&quot; alt=&quot;Two candidate generators — induced and autonomous — feeding an evaluation stage supplied by experiments, experience, external evidence and shared priors&quot; /&gt;
&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;encoded-and-held&quot;&gt;Encoded and Held&lt;/h2&gt;

&lt;p&gt;There is a second distinction cutting across those four sources, and it explains something engineering leaders argue about constantly without resolving.&lt;/p&gt;

&lt;p&gt;Evaluation capacity is either &lt;strong&gt;encoded&lt;/strong&gt; in artifacts or &lt;strong&gt;held&lt;/strong&gt; in people. Encoded capacity is the architectural fitness function running in CI, the runbook, the architecture decision record, the review checklist, the deployment gate. Held capacity is the staff engineer who knows why the payment reconciliation service behaves the way it does at month end.&lt;/p&gt;

&lt;p&gt;They fail in opposite directions.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/encoded-vs-held.svg&quot; alt=&quot;Encoded evaluation capacity compared with held evaluation capacity across replication cost, durability, novelty handling and update speed&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This resolves a question that otherwise looks like a matter of taste. A process-oriented organization can hire inexperienced engineers successfully, because the encoded capacity carries the judgment they do not yet have. A people-oriented organization making the same hire does worse — not because the person is worse, but because there is nothing for them to inherit. Neither model is superior in general; they are strong and blind in opposite places.&lt;/p&gt;

&lt;p&gt;The most interesting artifacts encode judgment about the future rather than the past. An architectural constraint expressed as an executable check is judgment someone wrote down once that now runs without its author. That is the strongest form encoded capacity takes, and its limit is the limit of the form: it evaluates what was anticipated and is silent about what was not.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-to-spend-it&quot;&gt;Where to Spend It&lt;/h2&gt;

&lt;p&gt;Evaluation capacity is scarce, which means it has to be allocated too — and spreading it evenly across every decision is the most common way to waste it.&lt;/p&gt;

&lt;p&gt;The rule that matters is reversal cost: what would it cost — in time, money and disruption — to undo this eighteen months from now if the assumption behind it turns out wrong. Low-reversal-cost decisions barely warrant evaluation; make them fast and correct cheaply. High-reversal-cost decisions warrant nearly all of it, because a wrong answer will still be constraining the organization long after everyone has forgotten the reasoning.&lt;/p&gt;

&lt;p&gt;What makes this difficult is that reversal cost has almost nothing to do with how large a decision feels at the time. Technology decisions have wildly different lifespans, and the range spans two orders of magnitude.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/decision-lifespan.svg&quot; alt=&quot;Technology decision lifespans from months to decades, with reversal cost rising across the range&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Past the middle of that range, a decision usually stops being visible at all — re-litigating it would mean re-litigating everything built on top, so nobody does.&lt;/p&gt;

&lt;p&gt;The mismatch is that most review processes calibrate scrutiny to &lt;em&gt;cost at the moment of commitment&lt;/em&gt;, not to lifespan. Choosing a primary language for a new service can be nearly free — a config file and an afternoon of debate — while carrying a fifteen-year reversal cost. An expensive one-off infrastructure migration might carry a three-year one. Calibrating by immediate cost systematically under-evaluates exactly the decisions that deserve the most evaluation.&lt;/p&gt;

&lt;p&gt;Reversal cost is not the whole picture, though. It asks what it takes to undo a decision; &lt;strong&gt;optionality&lt;/strong&gt; asks what future choices the decision leaves available, and the two come apart more often than they coincide. A vendor contract can be cheap to exit and still foreclose an entire category of architecture, because the integration pattern it encouraged has propagated everywhere. A platform can be expensive to unwind and still be the thing keeping three directions open. Reversal cost is about the past commitment; optionality is about the shape of the future.&lt;/p&gt;

&lt;p&gt;This is why platform work resists justification through delivery metrics. A platform’s return is not cheaper output this quarter. It is that a set of future decisions became affordable, and their consequences more predictable — which lowers the evaluation cost of everything built on top. Platform investment is evaluation-capacity infrastructure, and architecture that preserves optionality is the same purchase seen from another angle. Neither shows up in any measure of what shipped.&lt;/p&gt;

&lt;p&gt;One more effect is worth noticing: lifespan is often emergent rather than chosen. A database engine picked provisionally in year one is load-bearing by year three, because forty services now assume its consistency guarantees. Decisions become expensive to reverse while nobody is watching, so the window in which evaluation is cheap closes silently.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/reversal-cost-lifespan.svg&quot; alt=&quot;Reversal cost against decision lifespan, showing where evaluation capacity should be concentrated&quot; /&gt;
&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-economics-of-searching-well&quot;&gt;The Economics of Searching Well&lt;/h2&gt;

&lt;p&gt;Search costs something, which means a CTO is choosing how much of a scarce resource to spend on finding better ways to spend a scarce resource. Three ideas from economics do genuine work here, and they are not decorative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scarcity is the permanent condition, not a temporary shortfall.&lt;/strong&gt; Additional headcount moves the frontier of what is possible and immediately generates a larger set of things worth doing that still exceeds what is available — which is why “how do we get enough capacity” has no stable answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opportunity cost is the only honest price of a candidate.&lt;/strong&gt; Reviewed one at a time, almost every proposal clears the bar. The question that discriminates is not “is this worth doing” but “is this worth more than the next-best use of the same capacity” — and that alternative never names itself. Asking for it out loud is the cheapest search discipline available, because it forces a second candidate into existence at the moment the first is being approved. Without it, sequential local approval drifts somewhere nobody chose: every individual yes was defensible, and the accumulated pattern is an allocation no one would have selected deliberately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incentives determine which candidates exist at all&lt;/strong&gt;, which makes them the most consequential of the three and the easiest to miss. Teams propose what they are rewarded for proposing. If promotion follows visible launches, the candidate set reaching any review board is biased toward new surface area and away from platform work, debt reduction and decommissioning — not through bad faith, but because people rationally generate the options that are good for them to have proposed. The bias runs both ways: there is a well-worn path for the person who shipped an ambitious platform and essentially none for the person who recognised early that a funded initiative should stop. An incentive structure is a filter sitting upstream of governance, quietly determining which regions of the space are ever visited. Fixing the review board while leaving the filter in place changes little.&lt;/p&gt;

&lt;p&gt;To make any of this concrete, the split has to be measured rather than felt: a small number of tracked buckets — non-negotiable work to keep the business running, and elective investment across new capability, improvements to existing systems, and internal productivity.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/capacity-split.svg&quot; alt=&quot;Indicative ranges for keep-the-lights-on capacity across greenfield, established and legacy-heavy contexts, with a strain threshold&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The ranges above are indicative, not targets, and they move with domain, regulatory load and estate age — an AI-first product and a core banking platform have no business sharing a number. What matters is not landing on the right percentage but having one at all. A CTO who can state the current split, the intended split, and the direction of travel is in a different conversation from one who can only describe it qualitatively.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-ai-actually-changed&quot;&gt;What AI Actually Changed&lt;/h2&gt;

&lt;p&gt;Now the central asymmetry can be stated, and it is the reason the last three years feel confusing rather than simply good.&lt;/p&gt;

&lt;p&gt;AI is an extraordinarily powerful generation engine. It lowers the cost of producing a candidate — a prototype, a migration path, an alternative architecture, a working proof that something is possible — by an order of magnitude. In search terms it massively expands the number of points in the allocation space an organization can afford to visit. That is real, and it is the half everyone is discussing.&lt;/p&gt;

&lt;p&gt;AI simultaneously degrades evaluation capacity, and that half is invisible in every metric currently in use.&lt;/p&gt;

&lt;p&gt;The mechanism is the one I set out in &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt;: AI generates code faster than teams build understanding of it. Understanding was already the binding constraint on how large and complex a system a given team could hold. AI did not lift that ceiling — it compressed the timeline on which organizations reach it. With AI-authored code now accounting for somewhere between a third and two-thirds of what many teams commit, every system built substantially by generation rather than by authorship carries an evaluation cost that has been deferred rather than paid. And evaluation capacity is precisely what the organization needs in order to judge its &lt;em&gt;next&lt;/em&gt; allocation.&lt;/p&gt;

&lt;p&gt;The industry data carries this signature once you know to look. DORA’s research finds that AI amplifies whatever organizational discipline already existed rather than substituting for it — exactly what a technology that multiplies generation while leaving evaluation untouched would do &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. Teams with high evaluation capacity get more good candidates; teams without it simply get more candidates. The same work finds throughput and instability rising together in the same organizations, which is what a search process generating faster than it can judge looks like from the outside. And the persistent finding that a meaningful minority of developers do not trust AI output while shipping large volumes of it is not conservatism — it is a workforce accurately reporting that its evaluation capacity has not kept pace.&lt;/p&gt;

&lt;p&gt;Stated in terms of the thing that actually matters: an organization generating faster than it can judge is still accumulating output, but it has lost the ability to tell which of that output is building future capability and which is quietly consuming it. Both feel identical in the quarter they happen.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;AI made it cheap to try things and left it expensive to know whether they worked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/generation-evaluation-divergence.svg&quot; alt=&quot;Divergence between generation capacity and evaluation capacity over time in AI-assisted organizations&quot; /&gt;
&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-ai-can-and-cannot-evaluate&quot;&gt;What AI Can and Cannot Evaluate&lt;/h2&gt;

&lt;p&gt;That is too blunt as stated, and the qualification matters more than the headline. AI is not uniformly weak at evaluation — it is weak at a specific kind, and the boundary is worth drawing, because much of the current enthusiasm for feeding operational data to a model and asking what to do next sits on the wrong side of it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; described this loop working at the architecture layer — build something small, instrument it, let production failures feed back into tests and constraints — and named its limit: the loop can be made more reliable but not fully reliable, and the boundary is the depth of human understanding of the domain the system represents.&lt;/p&gt;

&lt;p&gt;That boundary generalises. Call the two sides &lt;strong&gt;closed-loop&lt;/strong&gt; and &lt;strong&gt;open-loop&lt;/strong&gt; decisions.&lt;/p&gt;

&lt;p&gt;Closed-loop decisions produce observable, attributable outcomes — latency, error rate, cost per transaction, rework rate, incidents thirty days out. The thing you chose actually ran and production said what happened. AI is genuinely strong here and getting stronger.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/closed-open-loop.svg&quot; alt=&quot;Closed-loop decisions return observable outcomes; open-loop decisions have no telemetry because the alternative was never built&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Open-loop decisions have no telemetry, because the alternative was never built. Whether to enter a segment. Whether to abandon a platform. Whether the next three engineers go to the migration or the new product. There is no log file for the counterfactual, and no amount of instrumentation on what you did do will produce one.&lt;/p&gt;

&lt;p&gt;Open-loop does not mean evidence-free, though. Borrowed evidence is exactly the third source described earlier, and aggregating it is something AI does very well — which genuinely raises the floor. Two limits survive. A published result came from a particular system, so whether it applies to yours is a separate judgment requiring understanding of yours; borrowed evidence relocates the question from “does this work” to “does this apply here,” which is the harder one. And organizations publish successes and instructive reversals, not the boring failures or the option nobody tried, so the corpus is a skewed sample and a model aggregating it inherits the skew without saying so.&lt;/p&gt;

&lt;p&gt;AI’s oldest commercial application states the boundary cleanly. Predicting markets from data has always been high-error and works anyway, because the bets are numerous, diversifiable and repeatable, so being wrong on any one averages out. That tolerance disappears when you are making one bet, once, with a high cost of reversal and nothing to average against.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Prediction with a wide margin of error is acceptable for reversible decisions and unacceptable for irreversible ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which is the uncomfortable shape of the current moment: AI raises evaluation capacity most for the cheap, reversible decisions that needed it least, and least for the expensive, one-way decisions where it was always binding. That does not make the reversal-cost discipline less important. It makes it the discipline that determines whether any of the new capability reaches the decisions that actually matter.&lt;/p&gt;

&lt;p&gt;Readers with a machine learning background will recognise the shape of this. Cheap candidates, expensive judgments, and a rule for choosing which candidates are worth judging is the structure of &lt;strong&gt;active learning&lt;/strong&gt;, with reversal cost acting as the acquisition function.&lt;/p&gt;

&lt;p&gt;The analogy is useful and it breaks in three places, which is where the organizational version stops being derivative. Active learning assumes an oracle — a label can always be bought. For an open-loop decision the label may not exist at any price, because the counterfactual was never run. It assumes a fixed labelling budget, whereas evaluation capacity &lt;em&gt;decays&lt;/em&gt; as people leave and reasoning goes unrecorded. And it assumes labels stay valid, while the conditions that made a past judgment correct keep moving.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-hybrid-team-is-a-search-system&quot;&gt;The Hybrid Team Is a Search System&lt;/h2&gt;

&lt;p&gt;The common framing — AI as tooling that makes engineers faster — describes an efficiency gain and misses the structural change. A mixed human-and-agent organization is a search system with the two arms handled by different participants: agents generating candidates at a rate no human team could match, humans holding the capacity to judge which are worth keeping.&lt;/p&gt;

&lt;p&gt;Three management problems follow, and they are the same problem. &lt;strong&gt;Review&lt;/strong&gt; is evaluation applied at the code level, and agents fail differently from people — confidently and fluently, producing output that reads as correct because it is well-formed. If generation volume rises while review depth holds constant, evaluation capacity per unit of output is falling even though nothing visibly changed. &lt;strong&gt;Accountability&lt;/strong&gt; cannot dissolve into the tool: “the AI did it” is no more valid in an incident review than “the linter did it,” so every class of consequential agent action needs a named human owner assigned before the agent has authority to act. And &lt;strong&gt;metrics&lt;/strong&gt; have to be attributed rather than aggregated, because a deployment figure blending human and agent work measures two processes as one at exactly the moment the difference matters.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;governance-as-routing&quot;&gt;Governance as Routing&lt;/h2&gt;

&lt;p&gt;With evaluation capacity named, governance can be defined more usefully than “who is allowed to decide.”&lt;/p&gt;

&lt;p&gt;Governance is not bureaucracy. Bureaucracy is what governance looks like when it is designed badly — uniform process applied regardless of stakes. Governance is decision architecture: the structure through which evaluation capacity is routed to the decisions that need it. Done well it is largely invisible, because low-stakes decisions move fast by design and only consequential ones slow down.&lt;/p&gt;

&lt;p&gt;That framing sharpens what usually goes wrong. Decision rights are allocated by structure — seniority, position, team boundary. Evaluation capacity is distributed by understanding, which respects none of those. Governance failures are, very often, authority sitting somewhere other than where the understanding sits.&lt;/p&gt;

&lt;p&gt;Knight Capital’s 2012 deployment failure — new trading code pushed to seven of eight production servers, a reused flag reactivating dormant functionality, roughly $440 million lost in forty-five minutes — was not an engineering failure. The engineers were competent and the code was ordinary. Nobody who understood what a partial deployment could do had authority at the moment it mattered. The failure was in routing.&lt;/p&gt;

&lt;p&gt;This also settles the centralisation argument, which is usually conducted as a matter of philosophy and is really a matter of variance. Authority should sit where the variance is. If regional conditions genuinely differ — different regulators, different payment rails, different fraud patterns — the understanding required to judge those decisions cannot be centralised, and centralising them destroys evaluation quality regardless of how capable the central team is. If variance is low, decentralising duplicates cost and fragments standards for nothing. Amazon’s 2003 API mandate is the clean software case: one interface standard imposed centrally with no exceptions, because there is no useful variance in how services should expose themselves, and everything behind the interface left to the team, because there is enormous variance in what each service actually does. Centralise where variance is low; delegate where it is high.&lt;/p&gt;

&lt;p&gt;Seen this way the governance domains stop being parallel checklists. Investment, risk, architecture, security, AI, vendor and compliance governance are seven attempts to route one class of decision each toward the place where it can actually be judged. Most implementations route toward hierarchy instead and assume comprehension coincides — which is an empirical question, and rarely asked.&lt;/p&gt;

&lt;div class=&quot;post-image&quot;&gt;
  &lt;img src=&quot;/assets/img/blog/evaluation-constraint/governance-domains-routing.svg&quot; alt=&quot;Seven governance domains, each routing a class of decision toward the evaluation capacity that can judge it&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The same lens sharpens the most familiar problem of all. &lt;strong&gt;Technical debt is not code; it is deferred understanding&lt;/strong&gt; — the reasoning behind a shortcut nobody recorded, held by a person who has since forgotten it or left. It hurts because it consumes future evaluation capacity: every subsequent decision touching that system costs more to judge, which is to say it draws down future capability by exactly the mechanism the earlier section described. This is also why agent-generated code that no one ever had to reason through carefully is a debt instrument even when the code is objectively good.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;when-resources-are-not-scarce&quot;&gt;When Resources Are Not Scarce&lt;/h2&gt;

&lt;p&gt;An obvious objection to all of this: what about organizations that do not face meaningful scarcity? A company with tens of billions in operating income can fund every candidate simultaneously and let the winners emerge. Does the constraint dissolve at that scale?&lt;/p&gt;

&lt;p&gt;It does the opposite. Abundance does not remove the constraint. It removes the mechanism that was doing the evaluating for free.&lt;/p&gt;

&lt;p&gt;Under scarcity the budget prunes automatically: a failing bet dies because you cannot fund it and payroll in the same quarter. That is a crude evaluation mechanism, but it is relentless and never forgets to run. Under abundance nothing prunes. The bet continues because continuing is affordable, and affordability is not information.&lt;/p&gt;

&lt;p&gt;Meta’s Reality Labs division accumulated roughly $83.6 billion in cumulative operating losses between 2020 and 2025, including a $19.19 billion loss in 2025 against $2.21 billion of revenue &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;. The reason that was survivable is the reason it went on so long: Meta’s total 2025 revenue was roughly $201 billion, and the core advertising business absorbed the burn without existential consequence. A capital-constrained company would have received the signal in year two, involuntarily. Meta received it when leadership eventually directed cuts of up to 30 percent to Reality Labs spending and reallocated toward AI — a decision made deliberately, years after a scarcer organization would have had it made for them.&lt;/p&gt;

&lt;p&gt;So the giant’s problem is not finding resources. It is that its automatic evaluation feedback has been switched off, and it now has to &lt;em&gt;manufacture&lt;/em&gt; the signal that scarcity used to supply. Kill criteria, scheduled reassessment and named ownership are optional for a startup, because the bank account enforces them anyway. At scale they are not optional. They are the only remaining mechanism.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;recovering-evaluation-capacity&quot;&gt;Recovering Evaluation Capacity&lt;/h2&gt;

&lt;p&gt;There is one more thing search requires, and it is the part most often mistaken for a separate discipline. Generating candidates and evaluating them once is not search — it is exploration. Search is what happens when the results of a commitment feed back and update the judgment applied to the next one. Revision is that feedback arm. Without it, an organization performs the motions of search and learns nothing from any of them.&lt;/p&gt;

&lt;p&gt;Evaluation capacity decays, which is what makes the feedback arm fragile. The reasoning behind a commitment fades, the people who could reconstruct it move on, and an initiative persists by default — not because anyone decided it should continue, but because nobody retains the capacity to determine that it should not. You cannot revise what you no longer understand, which is why organizations so often keep funding things nobody would start today, and why every year of that consumes future capability nobody recorded as spent.&lt;/p&gt;

&lt;p&gt;Three habits preserve it, and all three are cheap at the moment of commitment and expensive to retrofit afterwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set the kill criterion when you approve, not later.&lt;/strong&gt; A specific, named condition — a metric threshold, a competing option reaching a certain capability, a date by which a certain result should exist — decided while the room is still thinking clearly and before any sunk cost exists to bias the judgment.&lt;/p&gt;

&lt;p&gt;It is also the only common practice that records a counterfactual. Operational data captures what an organization did, almost nothing about what it rejected — which is why an organizational record, fed to a model or read by a successor, describes the past without helping anyone judge the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Schedule the reassessment rather than waiting for a crisis.&lt;/strong&gt; A commitment whose assumptions have quietly stopped holding does not announce itself. A fixed cadence is the forcing function a silent problem does not provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Name an owner for the reassessment, with the same clarity as the original approval.&lt;/strong&gt; Approval processes always name someone. The recheck is usually left to “the team should reassess if things change,” which means nobody is on the hook, which means it does not happen.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-uncomfortable-part&quot;&gt;The Uncomfortable Part&lt;/h2&gt;

&lt;p&gt;There is a tension here I do not think resolves cleanly, and it seems more honest to end on it than to manufacture a conclusion.&lt;/p&gt;

&lt;p&gt;The most reliable way to build evaluation capacity has always been to do the work. Engineers develop judgment about architectural trade-offs by making architectural mistakes and living with them; they learn which migrations go badly by being on the wrong end of one. The path to senior judgment runs through a large volume of low-stakes, hands-on repetition — and that volume is precisely the work agents are now absorbing most completely.&lt;/p&gt;

&lt;p&gt;So the organizations expanding their generation capacity fastest are, by the same action, eroding the mechanism by which their evaluation capacity has historically been renewed. Not immediately, and not visibly. But the engineers who will be judging allocations in 2032 are building their judgment now, on a smaller base of consequential experience than any previous cohort.&lt;/p&gt;

&lt;p&gt;I do not have a clean answer to this. The obvious remedies — deliberate rotation, protected hands-on work, structured post-mortems — all amount to paying deliberately for something the technology appears to offer free, which is a hard argument to win in a planning meeting and will get harder as the visible gap between generation-rich and generation-poor teams widens.&lt;/p&gt;

&lt;p&gt;What I am more confident about is the diagnostic. To tell whether an organization is searching or ratifying, do not look at how good its decisions appear. Ask how many allocations it seriously considered before choosing, and what it would have cost to evaluate one more. The answer to the second question is the constraint, and it is the one almost nobody measures.&lt;/p&gt;

&lt;p&gt;Which brings the argument back to where it started. Two organizations, sixty engineers each, the same budget, the same stack, the same backlog, five years apart in outcome. After everything above, the difference between them is no longer mysterious and it was never about talent.&lt;/p&gt;

&lt;p&gt;Both expanded their capacity to generate. Only one expanded its capacity to judge what it had generated — and so only one was ever really searching. The other ratified its way to a place nobody chose, one defensible decision at a time, and arrived with more code, more services, more shipped output, and less ability to do the next thing than when it started.&lt;/p&gt;

&lt;p&gt;Superior allocation was never a better quarter. It is a larger stock of future capability: the ability to absorb the regulatory change, enter the adjacent market, survive the platform shift that has not arrived yet. Every organization can see what it shipped. The ones that compound are the ones that can still tell what their choices did to what they will be able to ship.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;ref-1&quot;&gt;&lt;/a&gt;[1] Hall, S., Lovallo, D. and Musters, R. (2012). “How to put your money where your strategy is.” &lt;em&gt;McKinsey Quarterly&lt;/em&gt;, March 2012, and subsequent extensions of the same dataset published through 2016.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-2&quot;&gt;&lt;/a&gt;[2] Bower, J. L. (1970). &lt;em&gt;Managing the Resource Allocation Process&lt;/em&gt;. Boston: Harvard Business School Press. See also Bower, J. L. and Gilbert, C. G. (eds.) (2005), &lt;em&gt;From Resource Allocation to Strategy&lt;/em&gt;, Oxford University Press.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-3&quot;&gt;&lt;/a&gt;[3] Black, B. (2009). “EC2 Origins,” blog.b3k.us; and Amazon executive accounts of the September 2003 AWS vision document.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-4&quot;&gt;&lt;/a&gt;[4] Simon, H. A. (1955). “A Behavioral Model of Rational Choice.” &lt;em&gt;Quarterly Journal of Economics&lt;/em&gt;, 69(1), 99–118; Nobel Memorial Prize in Economic Sciences, 1978.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-5&quot;&gt;&lt;/a&gt;[5] Weill, P. and Woodham, R. (2002). “Don’t Just Lead, Govern: Implementing Effective IT Governance.” MIT Sloan CISR Working Paper. See also Weill, P. and Ross, J. W. (2004), &lt;em&gt;IT Governance&lt;/em&gt;, Harvard Business School Press.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-6&quot;&gt;&lt;/a&gt;[6] Burgelman, R. A. (1983). “A Model of the Interaction of Strategic Behavior, Corporate Context, and the Concept of Strategy.” &lt;em&gt;Academy of Management Review&lt;/em&gt;, 8(1), 61–70; and Burgelman, R. A. (1991), “Intraorganizational Ecology of Strategy Making and Organizational Adaptation.” &lt;em&gt;Organization Science&lt;/em&gt;, 2(3), 239–262.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-7&quot;&gt;&lt;/a&gt;[7] Amazon Prime Video Tech Blog (2023). “Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%.”&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-8&quot;&gt;&lt;/a&gt;[8] DORA / Google Cloud, &lt;em&gt;State of AI-assisted Software Development&lt;/em&gt;, 2025–2026 editions.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-9&quot;&gt;&lt;/a&gt;[9] Meta Platforms segment disclosures, FY2020–FY2025, as reported in company 10-K filings and quarterly earnings coverage.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;This post continues a series on the mechanics of technology leadership. Related pieces: &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt;, &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;, &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;The CTO Decision Stack&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/08/02/the-evaluation-constraint/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/08/02/the-evaluation-constraint/</guid>
      </item>
    
      <item>
        <title>The CTO Decision Stack in Startup and Enterprise</title>
        <description>&lt;h4 id=&quot;the-third-post-in-the-cto-decision-stack-series-the-seven-layers-dont-change-between-a-ten-person-startup-and-a-ten-thousand-person-enterprise-what-changes-is-what-each-layer-is-optimizing-for-given-different-constraints-a-startup-shipping-a-throwaway-product-to-win-a-deal-and-an-enterprise-refusing-to-is-not-one-of-them-being-undisciplined-both-can-be-right-in-their-own-context--and-the-recurring-failure-isnt-a-bad-decision-at-either-end-its-importing-a-tradeoff-that-was-correct-somewhere-else&quot;&gt;The third post in the CTO Decision Stack series. The seven layers don’t change between a ten-person startup and a ten-thousand-person enterprise. What changes is what each layer is optimizing for, given different constraints. A startup shipping a throwaway product to win a deal and an enterprise refusing to is not one of them being undisciplined. Both can be right, in their own context — and the recurring failure isn’t a bad decision at either end. It’s importing a tradeoff that was correct somewhere else.&lt;/h4&gt;

&lt;hr /&gt;

&lt;p&gt;A CTO who has spent a career at startups joins an enterprise and immediately tries to ship fast, skip the architecture review, and treat the first version as disposable. Three months in, a customer-facing outage traces back to exactly that posture, and it costs the company a contract renewal that took two years to win. A CTO who has spent a career at enterprises joins a startup and immediately stands up a formal RFC process, a dedicated platform team, and a multi-stage release pipeline. Eight months in, the startup runs out of runway, having shipped half as much as a leaner competitor with a fraction of the process.&lt;/p&gt;

&lt;p&gt;Neither CTO made a technically wrong call in isolation. Both made a call that was correct somewhere else.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/core-thesis.svg&quot; alt=&quot;Same layer, different constraint, different correct answer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is the actual subject of this post, and it’s worth being precise about what it isn’t. The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post in this series&lt;/a&gt; closed by noting that the stack behaves differently across organizational contexts, and named one axis of that difference: the startup’s risk is invisibility — decisions happening by default because nobody is positioned to make them deliberately — while the enterprise’s risk is disconnection — decisions made correctly in isolation by people who don’t know about each other. That axis is real, and it shows up below. But it isn’t the whole story.&lt;/p&gt;

&lt;p&gt;The deeper difference is what each layer is optimizing &lt;em&gt;for&lt;/em&gt;, given constraints that genuinely differ — not just how visible the optimization is. A startup choosing to build a deliberately throwaway product to win a deal isn’t a decision made invisibly by default. It can be fully deliberate and fully correct, for reasons specific to what a startup has and doesn’t have yet. An enterprise refusing the same call isn’t being slow out of habit. It’s protecting something the startup doesn’t have yet either.&lt;/p&gt;

&lt;p&gt;The seven layers are constant. What’s not constant is the answer each layer produces. The map below shows where each layer’s tension actually sits before the post walks through all seven in detail — and where a tension recurs at a later layer, it’s named once and referenced back to, not redefined.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/seven-layer-overview.svg&quot; alt=&quot;The seven layers, startup vs enterprise&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-1-corporate--business-strategy&quot;&gt;Layer 1: Corporate &amp;amp; Business Strategy&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Risk Appetite and Reputational Exposure.&lt;/strong&gt; An organization with a handful of customers and no public track record has comparatively little to lose from a visible failure. One with an existing customer base, existing contracts, and a brand built over years has a great deal to lose from the same failure. The same decision can carry a different expected cost depending on which of those is true, which means the rational threshold for “good enough to ship” genuinely differs — not because one company cares more about quality, but because the downside of being wrong is sized differently.&lt;/p&gt;

&lt;p&gt;This is why a startup can rationally choose, at layer one, to build a deliberately disposable product to win a specific deal, prove a market exists, or simply survive to the next funding round. It’s the sacrificial architecture posture the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post in this series&lt;/a&gt; described, in &lt;a href=&quot;https://martinfowler.com/bliki/SacrificialArchitecture.html&quot;&gt;Martin Fowler’s terms&lt;/a&gt; — building something now on the explicit understanding it will be discarded later. The posture is more available to a startup than it is anywhere else in a company’s life, precisely because the cost of the eventual public failure is low: few customers are exposed, there’s little brand to damage, and the capital clock is the binding constraint, so speed is worth more than durability against it.&lt;/p&gt;

&lt;p&gt;The same move costs an enterprise more. An enterprise weighing a similarly disposable build for a new initiative isn’t weighing it against a clean slate — it’s weighing it against an existing customer base who will experience the rough edges, and frequently regulatory or contractual exposure a startup hasn’t accumulated yet. An enterprise that ships something throwaway under its existing brand isn’t taking the same bet a startup takes. It’s taking a worse version of that bet, because the downside is sized to the company it already is. This is why enterprises rationally over-invest in quality and durability at layer one for new initiatives, even ones that are, in every other respect, startup-shaped. The investment isn’t conservatism for its own sake. It’s pricing the bet correctly against an exposure a startup doesn’t carry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invisibility and Disconnection.&lt;/strong&gt; The secondary tension at this layer is the one named in the introduction. A startup’s layer-one strategy is often founder intuition that’s never made explicit — frequently correct, rarely documented, hard to revisit when circumstances change because nobody can reconstruct what assumptions it depended on. An enterprise’s layer-one strategy is usually explicit and well-resourced, and its risk runs the other way: strategy decided in a room that doesn’t include anyone with current visibility into what the architecture can actually support, producing the disconnection the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; warned about between the technology SWOT and the business SWOT it’s meant to be checked against.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Technology SWOT, Run Twice.&lt;/strong&gt; The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; introduced the technology SWOT as the tool that surfaces what a business SWOT can’t see on its own — strengths, weaknesses, opportunities, and threats, evaluated from the technology side. The same four quadrants, run separately for a startup and an enterprise, produce almost mirror-image results, and the mirroring is the useful part.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/technology-swot-twice.svg&quot; alt=&quot;The technology SWOT, run twice&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is where time horizon and reversibility — the two axes the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; used to open each layer of the stack — do real work. A startup’s decisions tend to have short time horizons and high reversibility: a bet that doesn’t pay off can usually be unwound within a product cycle or two, because little has been built on top of it yet. An enterprise’s decisions tend toward long time horizons and low reversibility, not because enterprises choose this, but because scale itself extends both: more has been built on top of any given decision, more depends on it staying stable, and unwinding it later costs more the longer it’s been load-bearing. The technology SWOT for each context isn’t really describing two different sets of capabilities. It’s describing the same four quadrants, reshaped by how long a decision has to live and how much it costs to take back.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-2-product-architecture&quot;&gt;Layer 2: Product Architecture&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Resource Asymmetry.&lt;/strong&gt; An enterprise building a new product rarely starts from zero. Identity and authentication, billing, observability, compliance tooling, a design system, a deployment pipeline — these frequently already exist, built and hardened by other teams, available to a new initiative at close to no marginal cost. This changes what’s architecturally rational. An enterprise can afford more structural rigor up front on a new product than the same product would justify as an independent startup, because the cost of building “properly” is dramatically lower when most of what “properly” requires is already sitting on the shelf.&lt;/p&gt;

&lt;p&gt;A startup has no shelf. Every layer of the architecture is being built for the first time, by a team whose primary constraint is finding product-market fit before the runway runs out. Under-investing in architectural rigor at this stage is frequently the correct call — not a failure to plan ahead, but a recognition that the hours spent on structural cleanliness are hours not spent discovering whether the product needs to exist at all. The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt;’s Stripe example — the early bet that developer experience was the moat — was exactly this kind of startup-stage architectural decision, made deliberately and well, by a small team that chose where to spend its limited rigor budget rather than spreading it evenly.&lt;/p&gt;

&lt;p&gt;The risk in both directions is borrowing the other context’s answer. A startup that insists on enterprise-grade architectural rigor before it has product-market fit is spending a scarce resource — time — on a problem it doesn’t have yet. An enterprise that treats a new product’s architecture with startup-style looseness, assuming it’ll figure things out later, is declining resources it already owns for no real savings, and inheriting risk it didn’t need to take.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rewrite Tolerance.&lt;/strong&gt; Resource Asymmetry above is about the cost of building. This is about the cost of changing your mind once something is already built and already has users — a related but distinct constraint, because the two don’t move together.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/rewrite-cost-curve.svg&quot; alt=&quot;The cost of changing your mind, over time&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A startup with a small, early customer base can treat its own architecture the way the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt;’s Stripe example treated developer experience: as a bet that’s allowed to be wrong. If the bet doesn’t hold, the cost of rewriting is mostly internal — engineering time, not customer disruption — because there are few customers to disrupt. This is the sacrificial architecture posture from layer one, recurring here in its more literal, mechanical form: not just “we may discard this deliberately,” but “discarding this costs us comparatively little, so we can afford to let the architecture be wrong for a while before we know enough to make it right.”&lt;/p&gt;

&lt;p&gt;An enterprise product running at real scale doesn’t have that option. A rewrite isn’t mostly internal anymore — it’s a migration, with customers who have to be moved and a failure mode that’s visible to people who didn’t ask to be part of the experiment. This is precisely the condition the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post in this series&lt;/a&gt; described &lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781491986356/&quot;&gt;Neal Ford’s evolutionary architecture&lt;/a&gt; as answering: guided, incremental change, checked against fitness functions, rather than a wholesale rewrite that bets everything on the new version before the old one is retired. Part of why the enterprise can’t simply abandon the bet is that the same debt that was invisible at startup scale — an ugly schema, a brittle integration nobody outside engineering ever saw — tends to surface at enterprise scale as something a customer, an auditor, or a support team notices directly; it hasn’t just gotten more expensive to unwind, it’s become externally visible. The failure, predictably, is a startup refusing to rewrite out of misplaced caution it can’t afford, or an enterprise attempting a startup-style wholesale rewrite of a system already carrying real customer load.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-3-technology-delivery&quot;&gt;Layer 3: Technology Delivery&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Speed versus Rigor.&lt;/strong&gt; A startup’s fast-delivery culture — fewer review gates, lighter test coverage, a willingness to ship before everything is verified — is frequently a rational response to a runway clock. The cost of moving slowly, running out of money or losing a market window to a faster competitor, is usually higher than the cost of the technical debt incurred by moving fast, at least at the scale a startup is operating. This is a real trade-off, made consciously, not a quality failure.&lt;/p&gt;

&lt;p&gt;An enterprise’s slower delivery cadence — more review, more sign-off, more staged rollout — is the mirror calculation. At enterprise scale, a production incident doesn’t affect a small early cohort; it affects existing customers, existing contracts, and frequently SLAs with real financial penalties attached. The cost of moving carelessly is much higher than the cost of moving more slowly, so the rational trade-off shifts toward rigor — gatekeeping that earns its cost, not bureaucracy for its own sake, though as the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post in this series&lt;/a&gt; noted, AI’s effect on implementation speed is reshaping what “moving carefully” actually requires, and an enterprise that hasn’t revisited its review process against that shift is paying for rigor that no longer matches what’s actually slow. The failure, in either direction, is a startup adopting rigor it can’t afford the time for, or an enterprise importing speed into a context where the cost of being wrong is sized for a much bigger company than the one taking the risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build versus Buy.&lt;/strong&gt; A &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;dedicated post in this series&lt;/a&gt; already covered the mechanics of this decision — that AI makes building cheaper without changing the calculus for anything outside an organization’s core differentiation, and that the real question is who carries the operational burden once the thing exists. Startup and enterprise answer that question from opposite starting positions.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/build-buy-2x2.svg&quot; alt=&quot;Build versus buy: the binding constraint differs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A startup building something it should have bought is usually doing it for a reason the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post&lt;/a&gt; named directly: the build looks fast and the demo works, and the support burden that should have informed the decision doesn’t show up until much later, by which point the team has no spare capacity to absorb it. The startup’s real constraint on buying isn’t preference — procurement-grade vendors price for enterprise budgets, leaving a startup to build what it can’t afford to license, whether or not building is the right call on the merits.&lt;/p&gt;

&lt;p&gt;An enterprise facing the same decision can usually afford to buy almost anything; the constraint isn’t price, it’s process. Building, inside an enterprise, is often faster precisely because it routes around that process — not because building is cheaper in any absolute sense, but because it’s cheaper &lt;em&gt;relative to the friction of buying&lt;/em&gt; in that specific organization. &lt;a href=&quot;https://backstage.io&quot;&gt;Spotify’s Backstage&lt;/a&gt; is a clean instance of exactly this dynamic: the internal developer portal that eventually became an industry standard started as an internal tool built to solve Spotify’s own service-discovery problem, and one part of its appeal at the time was structural rather than technical — open-source, internally-built software is generally easier to get signed off than a comparable commercial purchase, because the decision doesn’t draw the same scrutiny a new vendor contract would. What actually separates the two contexts runs deeper than either price or process, though — it’s who is positioned to operate the thing once it’s running. An enterprise buying software is rarely just buying the software; it’s buying into existing security, platform, and SRE functions that already know how to operate a third-party dependency safely at scale. A startup buying the same software has none of that scaffolding to plug it into. This isn’t a claim about what kind of thing is being purchased — plenty of startups buy tools that deliver real operational leverage, plenty of enterprises buy tools that still require real in-house capability to run well. It’s a narrower claim: an enterprise usually has supporting functions already built to absorb the operational ownership a purchase brings with it, and a startup usually doesn’t, and that asymmetry is what should actually drive the build-versus-buy call in each.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-4-engineering-organization&quot;&gt;Layer 4: Engineering Organization&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Process Affordability.&lt;/strong&gt; A startup cannot afford a dedicated process function. There’s no spare capacity to run formal ceremonies, maintain an RFC process, or staff an architecture review board — the team is lightweight because lightweight is what the headcount allows, not necessarily because lightweight is philosophically preferred. Team structure accretes, ownership forms by default, and Conway’s Law — the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt;’s observation that any organization designing a system produces a design that mirrors its own communication structure — produces a system shape nobody designed on purpose, simply because nobody had the bandwidth to design it on purpose. The startup’s small size means Conway’s Law is operating on a communication structure that’s mostly informal, so the architecture it produces is whatever a handful of people happened to talk through in the moment.&lt;/p&gt;

&lt;p&gt;An enterprise starting a brand-new initiative faces the opposite temptation. The organizational muscle for process already exists and is already funded — sprint ceremonies, RFC templates, architecture review boards, a defined path for getting a new team stood up. Deploying that process on day one of a new product costs the enterprise comparatively little, because the infrastructure for it is sitting there. The risk is that the process was built for a mature, stable product, not a brand-new team still searching for its shape, and applying it uniformly can slow a new initiative down for no benefit the heavyweight process was actually designed to provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invisibility and Disconnection, again — but here it’s disconnection, not invisibility, that does the damage.&lt;/strong&gt; Where multiple teams exist at enterprise scale, each making a reasonable layer-four call about their own scope, the failure isn’t that the calls were wrong. It’s that none of the teams making them knew the other calls were being made. Amazon’s response to exactly this failure is one of the more explicit pieces of organizational engineering on record: &lt;a href=&quot;https://courses.cs.washington.edu/courses/cse452/23wi/papers/yegge-platform-rant.html&quot;&gt;a mandate&lt;/a&gt; that all teams expose their data and functionality only through service interfaces, with no other form of interprocess communication allowed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/api-mandate.svg&quot; alt=&quot;Before and after Amazon&apos;s interface mandate&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The widely cited two-pizza team sizing was secondary to this. The actual countermeasure was the interface mandate itself — a structural rule built specifically to prevent disconnection between teams that each had legitimate, independent ownership of their own slice of the stack. &lt;a href=&quot;https://stripe.com/guides/atlas/scaling-eng&quot;&gt;Stripe’s own scaling guide&lt;/a&gt; names the underlying shift in plainer terms: what works for fifty engineers may not work for ten or a thousand.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-5-people--talent&quot;&gt;Layer 5: People &amp;amp; Talent&lt;/h2&gt;

&lt;p&gt;This is where several of the tensions above converge. Resource asymmetry shapes who an organization can hire. Process affordability shapes how much governance it can run. Risk appetite shapes how much it’s willing to delegate before the consequences of delegating are fully understood. All three meet here, in decisions about who gets hired, where institutional knowledge ends up living, and how readily the organization can adopt AI without losing the judgment AI is meant to assist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Asymmetry and Risk Appetite, as in Layers 2 and 1, but together here.&lt;/strong&gt; A startup’s hiring is opportunistic by necessity — generalists who can cover multiple roles, because there’s no budget for narrow specialists and no headcount to spare for a dedicated governance function. Decisions about how much engineering work to delegate to AI agents, and who’s accountable when that output fails, get made ad hoc by whoever’s closest to the work, because there’s no one available to own the question as a distinct layer-five responsibility, exactly as the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; described.&lt;/p&gt;

&lt;p&gt;An enterprise can typically afford what the startup can’t: specialist hires, a dedicated AI governance committee, formal learning and development paths. But the existing machinery built for that resource advantage — leveling frameworks, compensation bands, hiring pipelines tuned for stable, well-understood roles — frequently doesn’t fit what a new, fast-moving initiative inside the enterprise actually needs. The enterprise has more resources at this layer and a real risk of misapplying them: importing a hiring and governance model built for a mature, low-risk product onto a team that needs to move and adapt the way a startup team would.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizational Memory.&lt;/strong&gt; A related but separate question is where an organization’s knowledge actually lives, and the two contexts answer it almost opposite ways.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/organizational-memory.svg&quot; alt=&quot;Where organizational knowledge lives&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In a startup, knowledge lives in people, because there’s been no time and no spare capacity to put it anywhere else — why a decision was made, what was tried and abandoned, what a particular piece of the system actually does under load, all of it sits in the heads of whoever was there when it happened. This is efficient until it isn’t: a startup can lose a single engineer and lose a meaningful fraction of its institutional context in the same afternoon, because nothing was written down to survive their departure.&lt;/p&gt;

&lt;p&gt;An enterprise’s knowledge lives in systems instead — documentation, onboarding material, architecture decision records, the formal processes the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; described as a layer-two artifact. &lt;a href=&quot;https://www.aboutamazon.com/news/workplace/an-insider-look-at-amazons-culture-and-processes&quot;&gt;Amazon’s own writing culture&lt;/a&gt; is an explicit, designed version of this: the six-page narrative memo required before any major decision exists specifically so the reasoning survives independent of whoever wrote it, and Amazon’s own account of why the practice works is direct about the goal — a good process doesn’t depend on a single scarce individual, and has a feedback loop built in regardless of who’s in the room. An enterprise can usually absorb the loss of any single person without losing the knowledge that person carried. The tradeoff is that building and maintaining those systems is itself a real cost, paid continuously, that a startup’s leaner approach simply doesn’t carry — until the day it needs to, and discovers the cost was deferred rather than avoided.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adoption Friction versus Investment Capacity.&lt;/strong&gt; AI adoption splits this layer in a direction that inverts the resource asymmetry rather than repeating it. A startup adopts AI tooling easily — no legacy process to reconcile it with, no governance committee to route through — but can’t invest deeply: no budget for a platform to manage agent output at scale, no spare time to build the fitness functions and guardrails the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post&lt;/a&gt; described as the real cost of adoption done well. It gets the easy half and has to skip the expensive half. An enterprise has the opposite problem: it can fund the expensive half outright — custom tooling, a staffed governance function, the observability investment that keeps AI-generated code traceable — but every new workflow still has to clear a security review and an approval chain sized for human-authored commits. This is the same process affordability advantage from layer four working against the enterprise rather than for it: the muscle that makes heavyweight process cheap to deploy also makes it expensive to bypass, even when bypassing it is exactly what fast AI adoption needs. Neither path is wrong — a startup’s fast, shallow adoption and an enterprise’s slow, deep one are both rational responses to what each can actually afford to do well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Supervision Paradox.&lt;/strong&gt; The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post&lt;/a&gt; named this directly: the skills required to supervise what an agent produces are the same skills delegating to the agent erodes, making unmanaged delegation a one-way ratchet. The mechanism is identical in both contexts; only the clock differs. A startup’s small team delegates heavily from day one because there’s no spare headcount not to, and because the team is small, the erosion concentrates in very few people — the organization’s entire supervisory capacity can thin out within one team’s tenure, with no bench to fall back on. An enterprise has that bench, but trades it for the pipeline problem the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;second post&lt;/a&gt; raised: the entry-level work that used to build supervisory judgment is exactly the work AI now does fastest, and a large organization can run that substitution for years before the gap is visible, because enough senior engineers can still catch agent errors that nobody notices the layer beneath them isn’t being trained the same way. The startup’s version of the paradox is fast and visible. The enterprise’s is slow, and doesn’t surface until the engineers who can still catch a mistake leave faster than they can be replaced.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-6-infrastructure&quot;&gt;Layer 6: Infrastructure&lt;/h2&gt;

&lt;p&gt;The same resource gap that shapes who an organization can hire shapes what it can build on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Asymmetry, as in Layer 2 — and this is the layer where it’s most durable and least disputable.&lt;/strong&gt; A startup provisions everything from scratch on commodity cloud, under real cost sensitivity, fragile under any load pattern nobody anticipated — not from carelessness, but because there’s no existing investment to inherit and no slack to over-provision against uncertainty. An enterprise building something new inherits infrastructure maturity for free: cloud commitments and the negotiating leverage that comes with them, an existing security and compliance posture, and — the clearest instance of this inheritance — observability. A failure in a brand-new enterprise product can often be traced with the same maturity as a failure in a ten-year-old one, because tracing infrastructure doesn’t care how old the product is, while a startup’s first real production failure is frequently also the first time anyone learns what the system does under load, debugged live with a customer watching. This is the enterprise equivalent of the layer-six economics the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; described in &lt;a href=&quot;https://www.datacenterknowledge.com/cloud/dropbox-s-reverse-migration-from-cloud-to-own-data-centers-five-years-on&quot;&gt;Dropbox’s decision&lt;/a&gt; to own its storage infrastructure once the cost curve justified it: a new enterprise initiative starts much further along that curve than a startup ever can.&lt;/p&gt;

&lt;p&gt;The risk runs in two directions, both familiar by now. The platform team that owns the inherited infrastructure optimizes for cost and standardization while the product team optimizes for delivery speed, and the two can work against each other even in good faith. And the inheritance itself is tuned to the failure modes of the enterprise’s existing, mature systems — a genuinely new kind of product, with unusual load patterns or a different architecture, can fall into gaps the inherited stack was never built to see. The advantage is real. It isn’t automatically the right advantage for what’s actually being built on top of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Infrastructure Makes Thinkable.&lt;/strong&gt; There’s a second, deeper claim hiding underneath Resource Asymmetry. The point above was about who has more infrastructure right now. This one is about something infrastructure does that has nothing to do with quantity: it determines which architectures are available to choose from at all, and that availability changes over time, in both directions.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/infrastructure-timeline.svg&quot; alt=&quot;What infrastructure makes possible changes over time, in both directions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781491986356/&quot;&gt;Neal Ford’s evolutionary architecture&lt;/a&gt; work makes the forward-pointing version of this directly: architects working before containerization existed couldn’t have built today’s default microservices patterns no matter how skilled they were, because the infrastructure those patterns depend on simply wasn’t there yet — the patterns weren’t undiscovered, they were unbuildable. A startup founded this year inherits that maturity for free. An enterprise’s core platform, built at an earlier point on the same curve, may still be carrying the constraints of whatever year it was actually built, unless it’s been actively modernized since.&lt;/p&gt;

&lt;p&gt;The same idea runs in the other direction too, and Amazon’s own infrastructure has supplied the clearest recent illustration of it. &lt;a href=&quot;https://www.wudsn.com/productions/www/site/news/2023/2023-05-08-microservices-01.pdf&quot;&gt;Prime Video’s video quality monitoring team&lt;/a&gt; had built its system as a distributed, serverless set of microservices — the architecturally fashionable choice and, at the scale they started at, a reasonable one. As the service scaled to monitor thousands of streams simultaneously, the architecture’s own coordination overhead became the cost, not the actual analysis work. Moving the service to a monolith cut infrastructure cost by over ninety percent and increased scaling capacity at the same time — not because microservices are wrong, but because the architecture correct at the scale Prime Video started at stopped being correct at the scale it grew into, and nobody had revisited the choice until the cost made it impossible to ignore. Prime Video didn’t abandon microservices as a whole; one service was refactored because it was the better fit for what that service had become. The lesson isn’t that monoliths outperform microservices, any more than the earlier point was the reverse. Architectural decisions are conditional on scale, workload shape, and infrastructure economics — and all three change, in both directions, which is what the diagram above and Prime Video’s experience are each describing from opposite ends.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-7-developer-productivity&quot;&gt;Layer 7: Developer Productivity&lt;/h2&gt;

&lt;p&gt;The infrastructure question has a close cousin one layer up: what an organization can build on shapes what its own engineers build with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Process Affordability and Resource Asymmetry, as in Layers 4 and 2, pulling in opposite directions here.&lt;/strong&gt; A startup’s tooling is whatever’s free and fast to adopt — there’s no capacity to invest in anything custom, so the developer experience is whatever the default setup provides, rarely a deliberate choice so much as the absence of one. An enterprise can lean on existing CI/CD, existing internal developer platforms, tooling investment built over years — a real advantage, but only when it actually fits the new initiative’s architecture the way the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt;’s Google example required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local versus Global Optimization.&lt;/strong&gt; The deeper reason that fit is so easy to get wrong is structural, not just a matter of checking carefully. A startup’s tooling decision optimizes for exactly one team — there’s only one team to optimize for, so the fastest available solution for that team is, by definition, the right answer. An enterprise’s platform team is solving a different problem entirely: not what’s fastest for any single team, but what’s good enough across dozens or hundreds of teams with different needs, none of which can be fully served by a solution tuned to any one of them. The heavyweight pipeline that feels like unnecessary friction to a new, fast-moving team isn’t usually a failure to optimize. It’s evidence of an optimization that was never aimed at that team specifically — a platform built to be tolerable everywhere rather than excellent anywhere, which is the correct objective at that scale and the wrong fit for a team that’s still small enough to be optimized for directly. The investment is real and well-funded either way. Whether it serves the team using it depends on whether anyone recognized which kind of optimization the team actually needed before applying the other one.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-transition&quot;&gt;The Transition&lt;/h2&gt;

&lt;p&gt;The tensions above don’t resolve gradually as a company grows. There’s a specific stretch where a company is too big for the tradeoffs that made sense as a startup and not yet positioned to draw on the advantages that make sense as an enterprise — and that stretch is the hardest part of the journey, for a structural reason worth naming directly.&lt;/p&gt;

&lt;p&gt;The startup-rational tradeoffs — ship fast, skip the architecture review, treat the first version as disposable, keep process light because there’s no one to run it — stop being rational the moment the constraints that justified them change. Reputational exposure grows as the customer base grows. The cost of a production incident rises as revenue starts depending on uptime. The capital clock that made speed worth more than durability stops being the most urgent constraint once there’s a real, paying customer base to protect. A company can cross this line without anyone deciding to.&lt;/p&gt;

&lt;p&gt;But the enterprise-rational advantages — existing infrastructure to lean on, existing process muscle to deploy cheaply, existing specialist talent to hire — usually aren’t available yet either. The infrastructure hasn’t been built. The process functions don’t exist. The talent pipeline hasn’t been established. A company in this stretch is carrying enterprise-sized exposure with startup-sized resources, which is precisely the gap that produces the costliest version of every failure described above: the public outage that costs a renewal, the runway burned on process the team didn’t need yet, the throwaway build shipped under a reputation the company can no longer afford to risk.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/transition-spectrum.svg&quot; alt=&quot;The transition is not a brief crossing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s worth being honest about how long this stretch actually lasts. The framing so far — startup, then transition, then enterprise — makes it sound like a brief crossing. It isn’t, for most organizations that experience it. A scale-up with a few hundred people, a fast-growing product company, a regional fintech with real customers and real revenue but nothing like an enterprise’s inherited infrastructure or process muscle: for companies like these, the transitional condition isn’t a phase to get through. It’s the operating environment, for years, possibly for the company’s entire life if it never reaches the scale where the enterprise-side advantages actually arrive. The seven layers and the tensions running through them apply just as much here as at either extreme — arguably more, since this is the zone where the cost of getting the calibration wrong is highest.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://stripe.com/guides/atlas/scaling-eng&quot;&gt;Stripe’s own framing of this point&lt;/a&gt; holds for the whole stack, not just engineering organization: accept that nearly everything set up today will stop working at some point, so design for flexibility, not perfection. The tradeoffs that got a company here were not wrong. They were scoped to a set of constraints the company has since outgrown, while the constraints that would justify the next set of tradeoffs haven’t fully arrived.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-collapse-pattern-revisited&quot;&gt;The Collapse Pattern, Revisited&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt; described three breakdown patterns common to any organization: strategic decisions masquerading as technical ones, technical decisions resolved at the wrong layer, and layer collapse under delivery pressure. A fourth pattern is specific to context, and it has two mirror-image forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Borrowing the wrong context’s tradeoff.&lt;/strong&gt; Neither failure here is a failure of execution. Both are a failure to notice that the tradeoff being applied was calibrated to a different set of constraints than the ones actually in play.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/startup-enterprise-cto-decision-stack/collapse-2x2.svg&quot; alt=&quot;Borrowing the wrong context&apos;s tradeoff&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The visibility failures&lt;/strong&gt;, still real, now correctly sized as one pattern among several rather than the whole story. The unstacked startup, where all seven layers are being decided invisibly by one or two people’s intuition, which works until the company outgrows what that intuition can personally span. The stacked-but-silent enterprise, where every layer has an owner making individually defensible calls, and the coordination cost of those calls never being compared is the kind of silo-driven inefficiency several research firms have separately estimated at somewhere in the range of a fifth to a third of total organizational capacity&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; — directionally consistent across sources even where the precise figure isn’t, and large enough that it rarely traces back to any single decision that was wrong.&lt;/p&gt;

&lt;p&gt;Both forms of the fourth pattern share the same root: a company that cannot explain, after the fact, why it ended up where it did — not because no one was deciding, and not because the decisions were bad, but because the decisions were each correct against a frame that nobody checked against the company’s actual, current constraints.&lt;/p&gt;

&lt;p&gt;One honest caveat belongs here. This post has argued, layer after layer, that startup and enterprise tradeoffs are each rational against their own constraints — and that framing does real work, but it isn’t a license to assume every decision is secretly optimal once you squint at it the right way. Constraints explain a great deal. They don’t excuse all of it. Founders stay attached to a call past the point it stopped serving them. Executives protect a structure for political reasons that have nothing to do with the constraints that originally justified it. Enterprises accumulate process nobody actually needs anymore and keep running it because removing it is its own kind of organizational labor nobody wants to spend. The diagnostic in this post is for telling apart a decision that’s correct for its context from one that’s wrong for any context — not for assuming the first category is the only one that exists.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;using-the-stack-across-contexts&quot;&gt;Using the Stack Across Contexts&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post&lt;/a&gt;’s diagnostic — for any significant decision, ask what layer it actually lives in, and whether it’s being evaluated at that layer — still applies without modification. What this post adds is a question that has to come before it, and the question is the same one at every layer: &lt;strong&gt;what do our actual constraints allow and require here, and is the tradeoff I’m reaching for one that was correct in a different context?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A startup CTO reaching for an enterprise’s rigor, and an enterprise CTO reaching for a startup’s speed, are making the same mistake in opposite directions: solving for a set of constraints they don’t actually have. The seven layers don’t change. What changes, predictably, is the answer each layer should give — and the CTO whose answer comes from the last company rather than this one will find a way to be wrong even while doing everything right.&lt;/p&gt;

&lt;p&gt;“Startup” and “enterprise” have been the names used throughout this post, because they’re the names most CTOs already use for the two ends of this range. But the actual mechanism was never about which label applies. It’s that a given constraint — low reputational exposure, a runway clock, an inherited platform, an established process function — produces a given answer, regardless of what the company calls itself. A two-hundred-person scale-up with enterprise-grade reputational exposure and startup-grade resources is not a confusing edge case for this model. It’s the model working exactly as described, for an organization that happens to sit in the middle of the range rather than at either end.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Martin Fowler, sacrificial architecture&lt;/strong&gt; — the concept of deliberately building a first version with the explicit intention of discarding it once it has served its purpose. &lt;a href=&quot;https://martinfowler.com/bliki/SacrificialArchitecture.html&quot;&gt;martinfowler.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neal Ford, Rebecca Parsons, and Patrick Kua, evolutionary architecture&lt;/strong&gt; — the framework for guided, incremental architectural change verified against fitness functions, including the argument that infrastructure availability (such as containerization) determines which architectural patterns are buildable at a given point in time. &lt;em&gt;Building Evolutionary Architectures&lt;/em&gt; (O’Reilly).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe’s engineering scaling guide&lt;/strong&gt; — including the framing that practices suited to fifty engineers may not suit ten or a thousand, and the caution against building out an engineering organization faster than it can absorb. &lt;a href=&quot;https://stripe.com/guides/atlas/scaling-eng&quot;&gt;stripe.com/guides/atlas/scaling-eng&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon’s service interface mandate&lt;/strong&gt; — the internal directive attributed to Jeff Bezos, requiring all teams to expose functionality only through service interfaces with no other form of interprocess communication allowed. The original 2011 internal Google memo by Steve Yegge that brought this account public was later taken down; it is preserved at multiple archival mirrors, including &lt;a href=&quot;https://courses.cs.washington.edu/courses/cse452/23wi/papers/yegge-platform-rant.html&quot;&gt;this course-hosted copy&lt;/a&gt; and &lt;a href=&quot;https://gist.github.com/kislayverma/d48b84db1ac5d737715e8319bd4dd368&quot;&gt;this archived gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon Prime Video, Video Quality Analysis architecture&lt;/strong&gt; — the team’s move from a distributed serverless microservices orchestration to a monolith, reducing infrastructure cost by over 90 percent and increasing scaling capacity. The original article on primevideotech.com has since been taken down; the full text is preserved in &lt;a href=&quot;https://www.wudsn.com/productions/www/site/news/2023/2023-05-08-microservices-01.pdf&quot;&gt;this archived PDF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon’s Working Backwards process&lt;/strong&gt; — the six-page narrative memo and PR/FAQ practice designed so that institutional reasoning survives independent of any single person, described in Colin Bryar and Bill Carr, &lt;em&gt;Working Backwards: Insights, Stories, and Secrets from Inside Amazon&lt;/em&gt; (St. Martin’s Press, 2021). An excerpt describing the process in Amazon’s own words is published at &lt;a href=&quot;https://www.aboutamazon.com/news/workplace/an-insider-look-at-amazons-culture-and-processes&quot;&gt;aboutamazon.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spotify’s Backstage&lt;/strong&gt; — the internal developer portal originally built to solve Spotify’s own service-discovery problem, later open-sourced and donated to the Cloud Native Computing Foundation. &lt;a href=&quot;https://backstage.io&quot;&gt;backstage.io&lt;/a&gt; and &lt;a href=&quot;https://engineering.atspotify.com/2025/4/celebrating-five-years-of-backstage&quot;&gt;Spotify Engineering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dropbox’s Magic Pocket migration&lt;/strong&gt; — the move of roughly 90 percent of Dropbox’s stored data off Amazon S3 onto self-built infrastructure between 2015 and 2016, disclosed in Dropbox’s 2018 S-1 filing as saving approximately $75 million in operating costs over the following two years. Reported in &lt;a href=&quot;https://www.datacenterknowledge.com/cloud/dropbox-s-reverse-migration-from-cloud-to-own-data-centers-five-years-on&quot;&gt;Data Center Knowledge&lt;/a&gt; and discussed, without external citation, in the first post of this series, &lt;em&gt;The CTO Decision Stack&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google’s internal developer tooling (Blaze/Bazel, Critique, Piper)&lt;/strong&gt; is discussed at length, without external citation, in the &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;first post of this series&lt;/a&gt;, &lt;em&gt;The CTO Decision Stack&lt;/em&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Ali Ahmed Thawerani writes about the systems, culture, and scale decisions that shape how technology organisations develop. TECTONICS publishes at &lt;a href=&quot;https://aathawerani.github.io&quot;&gt;aathawerani.github.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Estimates of silo-driven coordination loss vary by source and methodology, but several independent estimates land in a similar band. McKinsey’s &lt;em&gt;State of Organizations 2026&lt;/em&gt; and related operations research describe fragmented, cross-functional friction as consuming a substantial share of productive capacity (&lt;a href=&quot;https://www.mckinsey.com/capabilities/operations/our-insights/transform-the-whole-business-not-just-the-parts&quot;&gt;McKinsey &amp;amp; Company&lt;/a&gt;). A cross-source synthesis citing McKinsey, Bain, PwC, Gartner, and Okta research puts the figure at roughly 20–30 percent of operating expenditure lost annually to rework, miscommunication, and fragmented processes (&lt;a href=&quot;https://crebos.online/resource-center/the-true-cost-of-operational-inefficiency/&quot;&gt;Crebos&lt;/a&gt;). &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/</guid>
      </item>
    
      <item>
        <title>AI Across the CTO Decision Stack</title>
        <description>&lt;h4 id=&quot;ai-is-not-a-layer-seven-tool-it-is-a-force-that-changes-the-cost-structure-the-failure-modes-and-the-governance-requirements-of-all-seven-layers-at-once--and-most-organizations-are-only-managing-it-at-the-layer-where-it-first-became-visible&quot;&gt;AI is not a layer-seven tool. It is a force that changes the cost structure, the failure modes, and the governance requirements of all seven layers at once — and most organizations are only managing it at the layer where it first became visible.&lt;/h4&gt;

&lt;hr /&gt;

&lt;p&gt;The CTO Decision Stack is a seven-layer model for evaluating technology decisions — from corporate strategy down through product architecture, technology delivery, engineering organization, people and talent, infrastructure, and developer productivity tooling. &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;The CTO Decision Stack&lt;/a&gt; introduced the stack itself and &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt; introduced the ceiling that runs through it: the idea that every major architectural shift in software history was, underneath its specific vocabulary, an attempt to keep a system within the cognitive reach of the team responsible for it — and that the ceiling doesn’t disappear when the architecture changes, it moves.&lt;/p&gt;

&lt;p&gt;The previous post closed with a line that was a setup for this one, not a conclusion: AI does not belong to a single layer of the stack. This post takes that seriously, layer by layer — not by asking “how is AI used here,” which is the question that keeps the analysis trapped at layer seven, but by asking a sharper one: &lt;strong&gt;what does AI change about the criteria this layer is evaluated against, and what happens to the layers above and below when that change goes unacknowledged?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is a reason this question is hard to answer cleanly, and it is worth naming up front. Three things are true simultaneously, and most discussions of AI in engineering organizations collapse them into one.&lt;/p&gt;

&lt;p&gt;First, AI has genuinely lowered the cost of certain kinds of work — implementation, boilerplate, first-draft architecture, test scaffolding, migration scripting. This is real and should not be argued away.&lt;/p&gt;

&lt;p&gt;Second, AI has not lowered the cost of &lt;em&gt;understanding&lt;/em&gt; — and a meaningful fraction of what each layer of the stack actually does is understanding: understanding what the business needs, understanding what the architecture must absorb, understanding what the team can support, understanding who is accountable when something fails.&lt;/p&gt;

&lt;p&gt;Third — and this is the part that gets lost — &lt;strong&gt;the gap between these two costs is itself the new variable the stack has to account for.&lt;/strong&gt; When implementation gets cheap and understanding doesn’t, the gap between “how fast we can produce something” and “how well we understand what we produced” widens. That gap doesn’t sit quietly at one layer. It propagates — usually upward, usually invisibly, and usually on a delay long enough that by the time it’s visible, it looks like an unrelated problem.&lt;/p&gt;

&lt;p&gt;Two ideas recur throughout the seven layers below, in different forms each time. One is this gap itself — between the cost of acting and the cost of understanding what was done. The other is a sharper version of it specific to people: the engineering skills required to supervise what an AI agent produces are the same skills that delegating to the agent erodes — a one-way ratchet unless something deliberately works against it. Neither idea is entirely new in isolation. What’s new is that AI causes both to operate simultaneously across every layer of the stack, rather than in isolated pockets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/ai-across-cto-decision-stack/understanding_gap_propagation.svg&quot; alt=&quot;Understanding gap propagation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is, in other words, the cognitive load ceiling argument from earlier in this series, applied across the whole stack rather than just to architecture. The ceiling didn’t disappear when AI arrived. It moved — and at every layer of the stack, it moved to a different place, for a different reason, on a different timeline. Mapping where it moved, layer by layer, is the actual content of this post.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-1-corporate--business-strategy&quot;&gt;Layer 1: Corporate &amp;amp; Business Strategy&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; the half-life of the technology SWOT, and the assumptions a layer-one strategy is allowed to treat as stable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt; described the technology SWOT as the tool that surfaces what the business view of strategy cannot see on its own. The implicit assumption behind that tool — behind any SWOT — is that the four quadrants change slowly enough that a periodic review is sufficient. Annually, perhaps semi-annually for a fast-moving company. That assumption was already under strain before AI. AI breaks it more directly, because the rate of change in at least one quadrant — opportunities and threats arising from what AI-assisted teams can now build — is no longer compatible with an annual cadence.&lt;/p&gt;

&lt;p&gt;This isn’t a claim that strategy itself needs to move faster, which is a different and more dangerous idea — chasing a moving target by moving faster than it is a losing game, and that post was right that strategic decisions are defined by irreversibility, not speed. The claim is narrower: &lt;strong&gt;the inputs to the strategic review need to be refreshed more often than the strategic decisions themselves&lt;/strong&gt;, so that when a layer-one decision is made, it’s made against a current picture rather than a stale one that happens to still be sitting in last year’s SWOT document.&lt;/p&gt;

&lt;p&gt;There’s a second-order effect here that connects to a pattern &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles&lt;/a&gt; described: the cycle by which yesterday’s differentiator becomes today’s commodity and tomorrow’s table stakes. Software houses go through this with delivery models — bespoke work becomes product, product becomes commodity, and the cycle restarts with a new layer of differentiation built on top of what’s now commodity. AI is compressing that cycle specifically for &lt;em&gt;implementation capability&lt;/em&gt;. A custom integration, a bespoke internal tool, a differentiated workflow — categories of work that used to take a specialized team and represent real capability — are moving toward “anyone with AI assistance can build this” faster than the cycle previously ran. The layer-one question this raises isn’t “is our moat eroding” in the abstract. It’s: &lt;strong&gt;which of our current technology strengths are actually entries in last cycle’s SWOT that haven’t been re-evaluated against this cycle’s baseline of what’s now commodity-buildable?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The honest version of this for most organizations is uncomfortable: a capability that was a layer-one strength two years ago — “we have a team that can build X reliably, and most competitors don’t” — may now describe a capability that a much smaller team, AI-assisted, can approximate. Not replicate exactly, not match in depth, but approximate closely enough that the strategic value of the original capability has shifted from “we can do this and others can’t” to “we can do this well and others can do it adequately” — which is a different competitive position requiring a different strategy, even if nothing about the capability itself has changed.&lt;/p&gt;

&lt;p&gt;There’s a second strategic shift worth naming separately, because it isn’t about the SWOT at all — it’s about a posture that wasn’t really credible before and now is. If a future rewrite is cheap enough, an organization can rationally choose, at layer one, to under-invest in architecture deliberately: ship the disposable version now, optimize for time-to-market, and treat the eventual rebuild as a planned cost rather than a risk to be designed against. This is a layer-one decision in the fullest sense — it’s about risk appetite and competitive timing, not implementation detail — and AI genuinely makes it more viable than it used to be, in the same way Martin Fowler’s sacrificial architecture made deliberate, planned disposability a respectable engineering posture rather than a failure to plan ahead.&lt;/p&gt;

&lt;p&gt;The risk is not in choosing this posture. The risk is in choosing it at layer one and never saying so explicitly to the layers below. Fowler’s own version of the idea is careful on exactly this point: a sacrificial architecture still depends on modularity, so that what gets discarded is bounded and the discarding is graceful rather than wholesale. A layer-one decision to optimize for speed over durability is only as good as the layer-two decision that follows it about &lt;em&gt;where the seams are&lt;/em&gt; — which kind of disposability this is, and what’s allowed to be thrown away versus what has to survive the sacrifice. Made well, “we are deliberately building something sacrificial” is a legitimate strategic bet. Left implicit, it becomes indistinguishable from simply not deciding — and by the time it’s visible, it looks exactly like the architecture-by-reaction failure described at layer two below, except now it started one layer higher, as a choice nobody framed as one.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-2-product-architecture&quot;&gt;Layer 2: Product Architecture&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; the relationship between architectural decisions and the cognitive load ceiling that those decisions were always implicitly managing — and the timeline on which that ceiling is reached.&lt;/p&gt;

&lt;p&gt;This series has argued at length that every major architectural shift in the industry’s history — monoliths to microservices, layered architecture to Clean Architecture, ad hoc structure to DDD — was, underneath its specific vocabulary, a cognitive load management strategy. The architecture didn’t fail technically. It failed because the system outgrew the team’s collective ability to hold it in their heads, and the next architecture redistributed that load rather than eliminating it.&lt;/p&gt;

&lt;p&gt;Layer two, in the first post’s framing, is about designing for tomorrow’s changes rather than today’s requirements — making bets about which capabilities the product will need and how the system should be structured to absorb them. What AI adds to this is a second axis of “absorb”: not just whether the architecture can absorb &lt;em&gt;product&lt;/em&gt; change, but whether it can absorb the &lt;em&gt;rate of code generation&lt;/em&gt; that AI-assisted teams now produce, without the comprehension gap between what exists and what the team understands widening faster than the architecture’s natural seams can contain it.&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;architecture by reaction&lt;/strong&gt; pattern described in &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;, and it is worth being precise about what it is and isn’t, because the precision matters. Neal Ford’s &lt;em&gt;evolutionary architecture&lt;/em&gt; — guided, incremental change, with fitness functions checking each change against the architectural characteristics that matter — is the disciplined version of a system that changes constantly. Architecture by reaction is what’s left when the guidance is missing: AI addresses the problem directly in front of it at each stage — decomposing when scale demands it, introducing caching when latency demands it, reintroducing shared state when consistency demands it — without reference to &lt;em&gt;why&lt;/em&gt; an earlier architectural decision moved away from the pattern it’s now reintroducing. Each step is locally correct. The sequence regresses. It is, in other words, the failure mode evolutionary architecture exists to prevent — change without the fitness function that would have caught the regression — not a competing idea to Ford’s, and the credit for naming the cure belongs with him.&lt;/p&gt;

&lt;p&gt;The practical implication is one &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; has already named at the tooling layer — Architecture Decision Records, written so that the &lt;em&gt;rejected&lt;/em&gt; options and their rationale are preserved, not just the decision taken. What’s worth stating at layer two specifically is that &lt;strong&gt;this is now a layer-two artifact, not a layer-seven one.&lt;/strong&gt; An ADR that explains why a product architecture rejected shared state at a particular boundary is not documentation of a tooling decision. It’s the institutional memory that, paired with an actual fitness function checking for the regression, determines whether the architecture’s seams hold under AI-accelerated iteration or get quietly eroded one locally-correct change at a time.&lt;/p&gt;

&lt;p&gt;There’s a further wrinkle specific to AI that the cognitive-load framing makes visible. AI-generated code is, by the nature of how these models are trained, &lt;strong&gt;locally coherent but globally undisciplined&lt;/strong&gt; — any individual function or module looks reasonable, but the system-level properties that make an architecture an architecture (consistent dependency direction, enforced boundaries, the seams that make future decomposition possible) are not what the generation process is optimizing for. This means the layer-two question — where are the natural seams, and are the architectural boundaries aligned with them — now has a maintenance dimension it didn’t have before. The seams don’t just need to be &lt;em&gt;designed&lt;/em&gt;. They need a fitness function checking them, in Ford’s sense — an automated, ongoing test of the architectural characteristic that matters, not a one-time review — somewhere AI-assisted generation will encounter it as a constraint, or the seams will erode at the rate AI generates code that doesn’t know they’re there.&lt;/p&gt;

&lt;p&gt;The layer-two question, updated: &lt;strong&gt;are our architectural seams documented as intent, or encoded as constraints — and if generation outpaces the gap between those two, which one actually governs what gets built?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-3-technology-delivery&quot;&gt;Layer 3: Technology Delivery&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; the answer to the question this layer has always asked — can we actually deliver this, on what timeline, with what team, and once it’s in production can we support it and explain it when it breaks — for two distinct decisions that both live here: which stack to build with, and whether to build at all.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;Tech Stack Selection in the Age of AI Agents&lt;/a&gt; already covered the first in depth: AI coding capability is ecosystem-relative, calibrated to training data density rather than uniform across stacks, which makes stack choice an implicit choice about AI partner quality as much as a technical one — Python and TypeScript sit in the high-confidence core, with AI assistance shifting from asset toward liability the further a stack sits from it. That post also introduced the build-only-the-USP principle and the one-interface-file discipline for every external dependency. What’s worth adding here is that build-vs-buy is the same layer-three question as stack selection, asked one level up — &lt;strong&gt;both are ultimately asking who is going to own the operational reality of this thing once it exists&lt;/strong&gt;, and AI distorts the answer to both in the same direction.&lt;/p&gt;

&lt;p&gt;The naive read on build-vs-buy is that AI makes building cheaper, so the calculus should shift toward build. This is true for exactly one category — the core differentiated logic that is the actual reason the product exists, what’s sometimes called the USP. For everything else — the cross-cutting concerns every product has regardless of differentiation, and the domain-specific commodity services that exist because the problem is common enough that mature solutions already do it better than a bespoke build would — AI assistance doesn’t change the calculus much, because the comparison was never “can we build this” but “should the organization carry the operational burden of something that isn’t its differentiation.”&lt;/p&gt;

&lt;p&gt;What AI &lt;em&gt;does&lt;/em&gt; change is how visible the difference is at decision time. A build decision for something that should have been bought will, with AI assistance, &lt;em&gt;look&lt;/em&gt; like it’s going well during implementation — the first version comes together fast, the demo works, the timeline looks favorable. The support burden — the part of the lifecycle layer three actually cares about, the “when something breaks at 2am” question the first post used as its litmus test — is largely unaffected by how fast the implementation phase went. AI has made the part of the build-vs-buy decision that’s visible at decision time &lt;em&gt;less correlated&lt;/em&gt; with the part that determines whether the decision was right — exactly the same distortion happening to stack selection, where a fast first version in an AI-illegible stack can look like a good choice for months before the support burden becomes visible.&lt;/p&gt;

&lt;p&gt;This connects to the structural discipline that post named explicitly: &lt;strong&gt;every external dependency — bought or built — should sit behind one interface file.&lt;/strong&gt; Not as a tooling best practice, but as a layer-three risk management decision. If a build decision turns out to be wrong, the cost of reversing it is bounded by how many places in the codebase assumed the build’s specific shape. AI accelerates how fast those assumptions can spread through a codebase if they aren’t contained at a seam from day one — which means the cost of a &lt;em&gt;wrong&lt;/em&gt; build-vs-buy decision is now growing faster than it used to, even as the cost of &lt;em&gt;making&lt;/em&gt; the decision (in implementation time) has shrunk.&lt;/p&gt;

&lt;p&gt;The layer-three question, updated: &lt;strong&gt;for this decision — stack or build-vs-buy — is the implementation-time estimate we’re using actually informed by AI’s effect on implementation, or has it quietly become our estimate for the whole lifecycle, including the support burden AI doesn’t meaningfully accelerate?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-4-engineering-organization&quot;&gt;Layer 4: Engineering Organization&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; Conway’s Law gets a term in the equation it didn’t have before, and the implication runs in a direction most organizations aren’t expecting.&lt;/p&gt;

&lt;p&gt;Conway’s Law says systems mirror the communication structure of the organizations that build them. &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt; extended this directly: when a significant portion of a codebase is generated by AI operating without deep organizational context, the system stops mirroring the team responsible for it and starts mirroring something else — the statistical average of the training corpus, shaped by whatever architectural intent was actually encoded in the prompts and context at generation time. If that intent was thin, the system mirrors &lt;em&gt;nothing coherent at all&lt;/em&gt; — not the team, not the corpus average, just an accumulation of locally-reasonable decisions with no consistent referent.&lt;/p&gt;

&lt;p&gt;At layer four, this has a specific consequence for how ownership is assigned. &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt; described Amazon’s two-pizza team rule as fundamentally about ownership, not size — a team small enough to fully own a component, understand its behavior under load, and make architectural decisions about it without coordination overhead. That model assumes the component’s behavior is something the team’s collective understanding actually covers. If a meaningful share of a component was generated by AI working from context the team didn’t fully specify — and AI-generated code, per that post, defaults to &lt;em&gt;locally coherent but globally undisciplined&lt;/em&gt; patterns absent explicit architectural guardrails — then “the team owns this component” can become true in the org chart while becoming false in practice: the team is accountable for a system whose actual structure reflects decisions nobody on the team made deliberately.&lt;/p&gt;

&lt;p&gt;This is not a hypothetical drift. It’s the mechanism behind a pattern that’s become familiar fast: a component that “the team owns” but that, in practice, only two people on the team will touch — because those two people are the ones who’ve built up, through repeated exposure, an understanding of what the AI-generated parts of the system actually do that the rest of the team doesn’t have. The org chart says shared ownership. The reality is a knowledge bottleneck that looks like ownership until someone tries to make a change and discovers it isn’t.&lt;/p&gt;

&lt;p&gt;The countermeasure isn’t “review AI output more” — that’s a layer-seven response to a layer-four problem, and it doesn’t scale: a team of five with AI assistance can generate the volume that used to require twenty, but still has five engineers’ worth of review capacity. The real countermeasure is encoding the architectural intent that would otherwise have circulated informally — the “we tried that and it didn’t work” knowledge a co-located team normally shares through hallway conversation — into specifications, fitness functions, and ADRs with their rejected-options sections intact. &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; described this shift at the architecture layer as keeping the architecture coherent. At layer four, the same shift is what keeps &lt;strong&gt;ownership real&lt;/strong&gt;: it’s the difference between the org chart saying a team owns something and the team’s actual collective understanding being verifiable rather than concentrated in whichever two people happen to remember.&lt;/p&gt;

&lt;p&gt;The layer-four question: &lt;strong&gt;for the components our team structure says we own, is our collective understanding of those components something we could demonstrate — or does it currently live in the heads of whichever two people have been closest to the AI-generated parts?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-5-people--talent&quot;&gt;Layer 5: People &amp;amp; Talent&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; this is the layer &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt; identified as carrying the hardest open question — governance of the human-AI boundary, currently being decided ad hoc at layer seven by individual engineers, when it’s a layer-five decision about composition, accountability, and quality control. A year on, the shape of that gap is clearer, and it has a name from outside this series that &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; brought in: &lt;strong&gt;the supervision paradox&lt;/strong&gt;, first named by Lars Faye.&lt;/p&gt;

&lt;p&gt;The supervision paradox, in its sharpest form: the engineering skills required to supervise what an AI agent produces are the same skills that delegating to the agent erodes. The more you delegate, the less capable you become of catching what’s wrong — and the more you need that capability, precisely because more is being generated that could be wrong. This isn’t an argument against delegation. It’s an argument that &lt;strong&gt;delegation without a deliberate plan for where supervisory capability is maintained is a one-way ratchet&lt;/strong&gt; — and layer five is where that plan either exists or doesn’t.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/ai-across-cto-decision-stack/supervision_paradox_loop.svg&quot; alt=&quot;Supervision paradox loop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That post framed the layer-five development question as a skills shift: from implementation fluency toward specification precision, from code authorship toward architectural judgment, from debugging toward critical evaluation of agent output. What’s worth adding is &lt;em&gt;how&lt;/em&gt; that shift actually has to happen, because it doesn’t happen by osmosis, and the obvious mechanisms for developing it are exactly the ones AI adoption tends to remove first.&lt;/p&gt;

&lt;p&gt;Specification precision, architectural judgment, and critical evaluation of agent output are not abstract competencies. They’re built the way they’ve always been built — by doing the work, getting it wrong in ways that have consequences, and developing judgment from the gap between what you expected and what happened. The supervision paradox bites here specifically: if the most accessible entry-level work — the work junior engineers traditionally used to build these competencies — is now the work AI does fastest and most reliably, the organization has a pipeline problem it didn’t have before. Not “junior engineers are less necessary” — the opposite. &lt;strong&gt;The work that used to train the judgment senior engineers now need to supervise AI is disappearing from the pipeline at the exact moment that judgment is becoming more valuable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This reframes the layer-five governance question. It’s not just “who is accountable when agent output fails” — though that question, as that post noted, remains formally unanswered in most organizations and shows up as informal gatekeeping by whoever happens to be willing to push back hardest. It’s also: &lt;strong&gt;where, in this organization, is the next generation of people who can do that pushing back actually being developed&lt;/strong&gt; — given that the traditional development path runs through exactly the work AI is now absorbing?&lt;/p&gt;

&lt;p&gt;There’s a connected governance question that &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; makes concrete rather than abstract. That post described &lt;strong&gt;SpecOps&lt;/strong&gt; — specification authoring as a first-class engineering surface, with the architect’s primary responsibility shifting from designing systems directly to authoring the governance system that constrains AI generation: specifications precise enough to function as constraints, ADRs with rejected-options sections, fitness functions that enforce boundaries. That’s a layer-two and layer-six activity in terms of &lt;em&gt;what&lt;/em&gt; it produces. But &lt;em&gt;who does it&lt;/em&gt; and &lt;em&gt;how they’re developed&lt;/em&gt; is squarely layer five. An organization that has quietly let its senior engineers become full-time governance-system authors, while its junior engineers do AI-supervised implementation with no path toward governance-system authorship themselves, has made a layer-five decision about its future capability — almost certainly without recognizing it as one.&lt;/p&gt;

&lt;p&gt;The layer-five question, in full: &lt;strong&gt;if something agent-generated fails in production tomorrow, who is accountable — and separately, five years from now, who in this organization will have the judgment to have caught it, given how they’re being developed today?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-6-infrastructure&quot;&gt;Layer 6: Infrastructure&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; the same cost-curve question &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles&lt;/a&gt; described for cloud infrastructure, now playing out in real budget data — and a new category of infrastructure decision that didn’t exist before.&lt;/p&gt;

&lt;p&gt;That first post’s layer-six example was the cloud-versus-self-hosted crossover: a managed service that’s negligible at small scale becomes “quietly expensive” as usage grows, until the economics of owning the infrastructure outright start to beat the economics of renting it. The same crossover is now visible one level up, in how organizations are reallocating software budgets entirely. YipitData’s March 2026 SaaS Scoreboard tracked this directly: among large AI spenders, tools like Canva, Replit, and Vercel saw year-over-year spend increases of 70–100%, driven by AI-powered features and platform expansion, while several established hosted tools in the same portfolios — Asana, Twilio, Atlassian — saw spend fall by 20–45% over the same period, as teams reallocated budget toward the newer capabilities.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; The pattern isn’t simply “buy less of the old tool, buy more AI.” It’s two things happening at once: budget reallocating away from some hosted tools toward AI-native ones, and the hosted tools that survive doing so by becoming AI-plus-hosted hybrids, with usage-based AI credits layered on top of the seat-based subscription that used to be the whole bill.&lt;/p&gt;

&lt;p&gt;This is that first post’s cost-curve question, but the curve being evaluated has changed shape. It used to be a clean two-sided comparison — managed service versus self-hosted. It is now a three-way calculation: keep the hosted tool as-is, pay for the AI-upgraded version of the same hosted tool, or replace it with an AI-native alternative entirely — and the cost structure of all three is shifting underneath the decision faster than annual procurement cycles are built to track, because AI credits are usage-based in a way seat licenses never were. &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;Tech Stack Selection in the Age of AI Agents&lt;/a&gt; named the practical discipline that keeps any vendor crossover survivable regardless of which side of it an organization lands on: every managed service behind one interface file, so the eventual migration — hosted to AI-native, or seat-based to usage-based — is bounded to a single seam rather than a system-wide rewrite. That discipline was written for cloud services. It applies with at least equal force to whatever tool category is currently absorbing the AI-budget reallocation, because the same crossover, on a faster clock, is happening there too.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/ai-across-cto-decision-stack/governance_recurring_pattern.svg&quot; alt=&quot;Governance recurring pattern&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That cost-curve shape is itself an instance of something broader &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles&lt;/a&gt; documented across infrastructure, delivery models, process, and architecture: every previous cycle eventually discovered the governance it had been deferring. A phase that’s cheap and pragmatic at small scale generates its own cost or complexity as it scales, and the response is some form of governance — infrastructure governance, process governance, boundary governance — that the cheap phase had been implicitly postponing. The specific triggers differed each time. The shape didn’t.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Every previous cycle eventually discovered the governance it had been deferring. AI appears to be entering the same phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI-assisted development is in the early part of that arc, and it’s worth being precise about what “the same arc” means here — not a prediction that AI costs will spike the way cloud costs did, which is a narrower and more uncertain claim, but the broader and more observable one: a cheap, fast generation phase is producing a comprehension gap, the way cheap cloud produced a cost gap and lightweight process produced a coordination gap. Each of those gaps was eventually closed by governance — not by abandoning the cheap phase, but by adding the structure the cheap phase had been running without. There’s no reason to expect AI-assisted generation is exempt from that arc. The open question isn’t &lt;em&gt;whether&lt;/em&gt; comprehension governance arrives, but how early an organization builds it relative to when the gap becomes expensive to close.&lt;/p&gt;

&lt;p&gt;The second change at this layer is observability, and it connects directly to the institutional-memory argument from &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;. That post made the case that production failures are specifications the system wrote for itself — evidence of behavior the design didn’t anticipate — and that the value of this evidence depends on being able to trace a failure back to its architectural cause, not just its immediate symptom. That tracing has always depended on a chain of &lt;em&gt;why&lt;/em&gt;: why does this service call that one, why does this table have this column, why was this retry logic written this way. For human-authored code, that &lt;em&gt;why&lt;/em&gt; exists somewhere — in a commit message, in someone’s memory, in an ADR if the team was disciplined. For AI-generated code, the &lt;em&gt;why&lt;/em&gt; that existed at generation time was whatever was in the prompt and context — and unless that was captured, it doesn’t persist anywhere after the code is written. The code is the same either way. The &lt;em&gt;traceability&lt;/em&gt; of the code is not.&lt;/p&gt;

&lt;p&gt;This is the layer-six insight this framework specifically reveals: observability has always answered “what changed.” It now also has to answer “what reasoning was available when it changed” — and that can’t be reconstructed afterward by asking the person who made the change, if “the person” was an agent operating from context that no longer exists anywhere. A commit linked to a spec ID, an ADR ID, and a fitness function ID is traceable in the way the feedback loop &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; described requires — production failure to architectural cause to updated specification. A commit that’s just a diff with an AI-generated description of &lt;em&gt;what&lt;/em&gt; changed, with no link to &lt;em&gt;why it was asked for&lt;/em&gt;, is the layer-six equivalent of a system with no seams: functional, untraceable, and accumulating a debt that won’t be visible until someone needs the &lt;em&gt;why&lt;/em&gt; and finds it was never recorded. This is, in miniature, exactly the comprehension governance the arc above describes — the question is only whether it’s built before or after the gap it’s meant to close.&lt;/p&gt;

&lt;p&gt;The layer-six question, in full: &lt;strong&gt;is our AI-versus-hosted-tool spend sitting behind a seam we could reverse in one place, or has it already spread into every workflow that assumed the current tool would stay the current tool — and separately, when we need to know not just what changed but what reasoning was available when it changed, does our infrastructure have an answer, or are we waiting for the gap to become expensive enough to force one?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-7-developer-productivity&quot;&gt;Layer 7: Developer Productivity&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What AI changes:&lt;/strong&gt; the least, in terms of what this layer is &lt;em&gt;for&lt;/em&gt; — &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt;’s framing, that developer productivity tooling exists to make the architecture legible to the people building it, not to make engineers faster as an end in itself, holds completely. What’s changed is that this is now the layer where the &lt;strong&gt;perpetual rewrite loop&lt;/strong&gt; either starts or doesn’t.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling&lt;/a&gt; described that loop directly: AI accelerates code generation, comprehension debt accumulates faster than before, the system becomes unmaintainable sooner, a rewrite is initiated, AI accelerates the rewrite too, and the cycle restarts — each iteration faster and less understood than the last. The rewrite stops being a reset and becomes a treadmill. Crucially, that post argued this isn’t really about rewrites at all. It’s about whether the &lt;em&gt;forcing function&lt;/em&gt; that used to make architectural discipline economically necessary still exists. Historically, the prohibitive cost of a rewrite was what compelled organizations to invest in the disciplines — modular boundaries, clean separation, domain alignment — that made rewrites unnecessary. As AI lowers that cost, the forcing function weakens, and with it the economic pressure to maintain the disciplines in the first place.&lt;/p&gt;

&lt;p&gt;Layer seven is where this either gets caught or doesn’t, because layer seven is where the loop’s &lt;em&gt;speed&lt;/em&gt; is set. A CI pipeline that only checks “does it build and pass tests” is optimizing for the thing AI has made cheap — fast iteration — without any check on the thing AI hasn’t made cheap, which is whether each iteration is making the system more or less comprehensible. A CI pipeline that includes fitness functions — the architecture-as-code constraints &lt;a href=&quot;https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt; described, dependency rules that fail the build regardless of who or what generated the violating code — is the layer-seven mechanism that keeps the loop’s speed from outrunning the team’s ability to keep the system within reach.&lt;/p&gt;

&lt;p&gt;This is the precise sense in which layer seven’s tooling decisions have layer-two and layer-six consequences that don’t stay at layer seven. A team that adopts AI coding assistance — a layer-seven decision, correctly evaluated as one — without also investing in the fitness functions and architectural constraints that would catch drift has made half of a decision. The half they made is visible immediately — faster PRs, quicker first drafts. The half they didn’t make is invisible until the comprehension gap it should have been closing has widened enough to surface as something else: the layer-four ownership bottleneck, the layer-six untraceable change, the layer-one strategic assumption that quietly stopped holding.&lt;/p&gt;

&lt;p&gt;There is a version of cheap rewrites that isn’t the treadmill described above, and it’s worth distinguishing the two clearly. Martin Fowler’s &lt;em&gt;sacrificial architecture&lt;/em&gt; — building something now on the explicit understanding that it will be deliberately discarded later, with the team that built it deciding when — is not the same thing as the perpetual rewrite loop, even though both involve rewriting and both are made more viable by AI. The difference is intent and modularity. A sacrificial architecture is planned: the team knows roughly what’s disposable, keeps the seams clean enough that the sacrifice can happen in pieces rather than wholesale, and treats the eventual rewrite as a milestone rather than an emergency. The perpetual rewrite loop is the same cheap-rewrite capability &lt;em&gt;without&lt;/em&gt; that planning — full-system rewrites triggered by accumulated comprehension debt rather than a deliberate decision, each one as undisciplined as the system it replaces, because nothing about the rewrite itself enforces the modularity that would let the next sacrifice be partial instead of total. AI lowers the cost of both. Layer seven’s fitness functions are what determines which one an organization actually gets.&lt;/p&gt;

&lt;p&gt;The layer-seven question, restated from that post’s framing but pointed specifically at this layer’s role in the loop: &lt;strong&gt;has adopting AI tooling here made our iteration loop faster without making our comprehension loop faster too — and if so, which one is currently setting the pace for the other?&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-collapse-pattern-revisited&quot;&gt;The Collapse Pattern, Revisited&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt; described three breakdown patterns: strategic decisions masquerading as technical ones, technical decisions resolved at the wrong layer, and layer collapse under delivery pressure. Looking across all seven layers above, a fourth pattern emerges that’s specific to AI — not a replacement for the first three, but a description of how AI tends to produce all three at once, through a single mechanism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI adoption decisions are made at layer seven, with layer-seven criteria, correctly — and then nothing else happens.&lt;/strong&gt; The decision itself isn’t wrong; that first post was explicit that tooling decisions belong at the tooling layer. The failure is that adoption at layer seven creates &lt;em&gt;open questions at every layer above it&lt;/em&gt; — does the technology SWOT still hold, do the architectural seams survive the new generation rate, does the build-vs-buy calculus actually shift or only appear to, does ownership still mean what the org chart says, does the governance model exist or is it de facto, can failures be traced to their causes, is the iteration loop outrunning the comprehension loop — and the layer-seven decision answers none of them, but gets treated as though it does, simply because it’s the decision that was actually made.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/ai-across-cto-decision-stack/collapse_pattern_six_open_questions.svg&quot; alt=&quot;Collapse pattern six open questions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is layer collapse running in a direction that post’s framing didn’t quite anticipate: not a strategic question answered with operational criteria, but an operational decision, correctly made, generating consequences that propagate upward through layers where the &lt;em&gt;equivalent decision was never made at all&lt;/em&gt;. Six open questions, one closed one — and the gap between them is the same gap between acting and understanding that runs through this entire post.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;using-the-stack-for-ai-decisions&quot;&gt;Using the Stack for AI Decisions&lt;/h2&gt;

&lt;p&gt;The diagnostic from &lt;a href=&quot;https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;“The CTO Decision Stack”&lt;/a&gt; still applies without modification: for any significant AI-related decision, ask what layer it actually lives in, and whether it’s being evaluated at that layer. What this post adds is that for AI specifically, the diagnostic needs to be run &lt;strong&gt;seven times for every adoption decision&lt;/strong&gt;, not once — because the adoption decision answers layer seven’s question and leaves the other six open by default, not by choice.&lt;/p&gt;

&lt;p&gt;The organizations that will navigate this well are not the ones that adopted AI fastest, and not the ones that adopted it most cautiously. They’re the ones that, having made the layer-seven decision — which most organizations have already made, one way or another — went back through layers one to six and asked, deliberately, whether anything there needed to change in response. Most of the time, for most layers, the honest answer will be “not yet, but here’s what we’re watching for.” That answer is fine. What isn’t fine is the question never being asked — because the gap between implementation cost and understanding cost doesn’t go away when it’s not asked. It just accumulates somewhere else, on someone else’s timeline, until it arrives looking like a different problem entirely.&lt;/p&gt;

&lt;p&gt;The CTO Decision Stack exists to make layers visible before their consequences arrive. AI is the fastest-moving test that visibility has faced — not because it’s more disruptive than previous shifts, but because it’s the first one where the cost of &lt;em&gt;acting&lt;/em&gt; and the cost of &lt;em&gt;understanding&lt;/em&gt; have moved in opposite directions at the same time. The implementation-understanding gap is the structural problem; the supervision paradox is its human manifestation, the same gap showing up in what people are and aren’t able to catch. Every layer of the stack was, in some sense, built to manage exactly that gap. This is just the first time all seven have had to manage it simultaneously.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Ali Ahmed Thawerani writes about the systems, culture, and scale decisions that shape how technology organisations develop. TECTONICS publishes at &lt;a href=&quot;https://aathawerani.github.io&quot;&gt;aathawerani.github.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;YipitData, &lt;em&gt;SaaS Scoreboard&lt;/em&gt;, March 2026, as reported in SpendHound, &lt;a href=&quot;https://www.spendhound.com/blog/best-saas-spend-management-software&quot;&gt;“14 Best SaaS Spend Management Software in 2026,”&lt;/a&gt; May 1, 2026. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 14 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/2026/06/14/ai-across-cto-decision-stack/</guid>
      </item>
    
      <item>
        <title>The CTO Decision Stack</title>
        <description>&lt;h2 id=&quot;seven-layers-of-decision-making--and-why-conflating-them-is-how-technical-leadership-breaks-down&quot;&gt;Seven layers of decision-making — and why conflating them is how technical leadership breaks down&lt;/h2&gt;

&lt;hr /&gt;

&lt;p&gt;There is a category of technical leadership failure that does not announce itself as a failure at the time it happens.&lt;/p&gt;

&lt;p&gt;A CTO makes a call about the database. It is the right call, technically. Clean, defensible, well-reasoned. Six months later, the engineering team is reorganized around it in ways that nobody planned. The product roadmap is constrained by it. The hiring strategy has implicitly shifted because of it. The company is now three layers deep into consequences that originated from a decision that was framed, evaluated, and made as a purely technical question.&lt;/p&gt;

&lt;p&gt;This is not a story about a bad decision. It is a story about a decision made at the wrong layer — evaluated against the wrong criteria, with the wrong people in the room, without visibility into the implications it would carry upward.&lt;/p&gt;

&lt;p&gt;The CTO role is structurally unusual in organizations. Unlike a CFO, who operates within a fairly well-understood set of financial abstractions, or a CPO, who owns a reasonably bounded product domain, the CTO sits at an intersection between corporate strategy, product thinking, operational delivery, organizational design, people leadership, infrastructure, and developer tooling. These are not the same type of problem. They do not respond to the same reasoning. They do not decay at the same rate or carry the same reversibility.&lt;/p&gt;

&lt;p&gt;Most technical leaders know this in principle. The difficulty is that in practice, the layers collapse. A decision that should live at one layer gets resolved at another. Strategic questions get answered by whoever happened to be in the room for a technical discussion. Infrastructure choices calcify into product constraints. A technology choice gets evaluated on architectural merit alone, without anyone asking whether the team can deliver it or sustain it in production. Developer tooling decisions accumulate into organizational culture, invisibly, over years.&lt;/p&gt;

&lt;p&gt;The CTO Decision Stack is an attempt to make the layers explicit — not as a hierarchy of importance, but as a map of where decisions actually belong, what they are optimizing for, and how they interact with each other.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-seven-layers&quot;&gt;The Seven Layers&lt;/h2&gt;

&lt;p&gt;The stack runs from the highest level of abstraction to the most operational. Each layer has its own time horizon, its own reversibility profile, and its own failure mode when it is confused with another layer.&lt;/p&gt;

&lt;p&gt;They are not independent. Every layer has load-bearing relationships with the layers above and below it. A decision at one layer creates the environment within which decisions at adjacent layers must be made. This is what makes them a stack, not a list.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cto-decision-stack/cto-decision-stack.svg&quot; alt=&quot;CTO Decision Stack&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-1-corporate--business-strategy&quot;&gt;Layer 1: Corporate &amp;amp; Business Strategy&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Years to decades. Reversibility: Very Low.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The top layer is the one technical leaders most often underweight — not because they do not care about business outcomes, but because decisions at this layer do not feel like engineering decisions. They feel like someone else’s problem.&lt;/p&gt;

&lt;p&gt;They are not.&lt;/p&gt;

&lt;p&gt;This layer operates at two altitudes that are distinct but inseparable. Corporate strategy sits above business strategy. Corporate strategy asks: what is the shape of the organization itself — its portfolio of bets, its approach to M&amp;amp;A, its decision about which capabilities to own versus acquire versus partner on? A CTO who has not engaged with these questions will find that the answers arrive anyway, embedded in decisions made by others, and discover too late that those answers have constrained everything below.&lt;/p&gt;

&lt;p&gt;Business strategy sits just below it, and asks the question most technical leaders are more comfortable with: what does this specific product or business unit need to be, technically, to win in its market over the next several years?&lt;/p&gt;

&lt;p&gt;But neither question can be answered in isolation from the environment the organization operates in. External forces shape the answer before the CTO gets to ask it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market dynamics&lt;/strong&gt; determine what speed of evolution is required. A market that is moving fast with low switching costs demands different architectural choices than one that moves slowly with deep integration. A CTO building for a fast market who optimizes for stability is playing the wrong game. One building for a slow market who optimizes for speed is accumulating unnecessary complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talent pool and availability&lt;/strong&gt; constrain what is actually buildable. A technically correct strategy that requires skills the market cannot supply is not a strategy — it is a fantasy. Stack choices, hiring models, and organizational design all feed back into what the layer-one strategy can credibly commit to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Competition and coopetition&lt;/strong&gt; define where differentiation is actually possible. Competing head-on against a well-resourced incumbent on their strongest capability is a different strategic position than identifying the adjacent surface they cannot serve. And coopetition — building on top of a competitor’s platform, contributing to shared infrastructure with rivals, participating in industry consortia — carries its own set of layer-one decisions about what to share and what to protect.&lt;/p&gt;

&lt;p&gt;These forces are not layers in themselves. They are the environment within which layer-one decisions are made — the constraints that make some strategies viable and others academic. The CTO’s job at this layer is not to predict external forces, which is impossible, but to make strategic decisions that are robust to a range of plausible futures rather than optimized for a single assumed one.&lt;/p&gt;

&lt;p&gt;This is precisely the role that enterprise architects were invented to fill — the bridge between corporate strategy and technology structure. In most organizations that role is either absent, underpowered, or disconnected from real decisions. The gap does not stay empty. It fills itself with accumulated accidents: technology choices that were never evaluated against strategy, architectural decisions that carry strategic consequences nobody intended, organizational structures that reflect the company as it was rather than the company it needs to become. The CTO who does not explicitly own layer one is not avoiding the work. They are delegating it to nobody — and discovering later that nobody did it.&lt;/p&gt;

&lt;p&gt;The practical tool at this layer is a technology SWOT — distinct from and complementary to the business SWOT the executive team runs. The business SWOT analyzes market position, commercial strengths and weaknesses, competitive threats, and external opportunities. The technology SWOT runs the same analysis from the technology perspective and surfaces things the business view cannot see.&lt;/p&gt;

&lt;p&gt;Technology &lt;strong&gt;strengths&lt;/strong&gt; are the capabilities the organization has built that competitors would find hard to replicate: proprietary data assets, engineering culture, technical infrastructure that enables speed or reliability at scale. Technology &lt;strong&gt;weaknesses&lt;/strong&gt; are the accumulated constraints that limit strategic options: architectural debt that makes certain product directions prohibitively expensive, skill gaps that make certain approaches unexecutable, operational fragility that caps the pace of change the organization can absorb. Technology &lt;strong&gt;opportunities&lt;/strong&gt; are the external developments — new tools, new platforms, shifts in the talent market, emerging AI capabilities — that the organization is positioned to exploit before competitors do. Technology &lt;strong&gt;threats&lt;/strong&gt; are the forces that could erode current advantages: commoditization of capabilities that were once differentiators, platform shifts that require architectural reinvention, AI tools that allow smaller competitors to close the capability gap faster than anticipated.&lt;/p&gt;

&lt;p&gt;The business and technology SWOTs should be run together and compared explicitly. Where they diverge is where the most important layer-one conversations happen: a business opportunity that the technology SWOT reveals as unexecutable, a technology strength that the business has not yet found a way to monetize, a technology threat that the business has not yet registered as a strategic risk.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cto-decision-stack/technology-swot.svg&quot; alt=&quot;Technology SWOT&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Strategic decisions are defined by their irreversibility, not their importance. A decision that cannot be undone in under six months is a strategic decision, regardless of how it was framed when it was made.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The questions that belong at this layer: what is the defensible technical moat, if any? Where does software differentiation matter and where is it commodity? What engineering capabilities need to exist in-house, and which can be bought, rented, or partnered for? Are there capabilities where coopetition produces more value than independent investment? What does the talent market allow us to credibly build?&lt;/p&gt;

&lt;p&gt;The clearest illustration of a layer-one decision made correctly is Stripe’s early bet that developer experience was the moat. Not features, not pricing, not distribution — the quality of the API and the quality of the documentation. That was not an engineering decision. It was a corporate strategy decision about what the company would be. It shaped everything below it: the product architecture had to be clean enough that the API surface was genuinely pleasant to use, the engineering organization had to value craft in ways that could sustain a developer-first culture, and infrastructure had to prioritize reliability because an unreliable payment API is not a moat. A single strategic call at layer one propagated through every layer beneath it for years.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cto-decision-stack/decision-propagation.svg&quot; alt=&quot;Decision propagation&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-2-product-architecture&quot;&gt;Layer 2: Product Architecture&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Months to years. Reversibility: Low.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second layer is where technical strategy becomes technical structure — where the business’s intent to build a specific kind of product is translated into the architectural decisions that will shape how that product can evolve.&lt;/p&gt;

&lt;p&gt;This is the layer most CTOs feel most at home in. It is the layer of system design: how is the product decomposed, how do its components communicate, where are the boundaries drawn, what are the contracts between services, how is data modeled and owned, what are the consistency and availability properties the system needs to have. The primary criteria here are scalability, security, resilience, and the system’s capacity to absorb change without structural collapse.&lt;/p&gt;

&lt;p&gt;But framing it as pure technical design misses what makes it hard.&lt;/p&gt;

&lt;p&gt;Product architecture decisions are not evaluated against technical correctness. They are evaluated against a product roadmap that does not yet fully exist. The architect is making bets about which capabilities the product will need, in what order, at what scale. A decision that is correct for the product as it exists today may be deeply wrong for the product as it will need to exist in eighteen months. A system designed for a single-tenant model will not cleanly become multi-tenant. A system built around a monolithic data model will not cleanly decompose. A system optimized for read-heavy access patterns will not gracefully absorb write-heavy load.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The job of product architecture is not to design for today’s requirements. It is to design for tomorrow’s changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The failure mode at this layer is premature optimization in either direction. Too rigid, and the architecture cannot absorb the product evolution that is inevitable. Too loose — “we’ll figure it out when we get there” — and the product accumulates structural debt that makes each evolution more expensive than the last until some transitions become effectively impossible.&lt;/p&gt;

&lt;p&gt;The questions that belong here: where are the natural seams in the product domain, and are the architectural boundaries aligned with them? Which parts of the system need to evolve independently, and are they actually independent? What are the data models that are most expensive to migrate, and are they designed to survive product changes? What are the external interfaces — to customers, to partners, to regulators — and are they stable even when internals change?&lt;/p&gt;

&lt;p&gt;Netflix’s migration from a monolith to services is the canonical example of a layer-two decision made correctly — but only in retrospect. The decomposition was not driven by technical elegance. It was driven by a product requirement: different parts of the system needed to scale independently because different parts of the product experienced radically different load profiles. The recommendation engine, the streaming pipeline, and the user account service had nothing in common in terms of their scaling needs. The architecture had to reflect that, or the product could not evolve to meet it. The organizational restructuring that followed — separate teams, separate ownership, separate deployment pipelines — was not a consequence of the architecture. It was required by it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-3-technology-delivery&quot;&gt;Layer 3: Technology Delivery&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Months to years. Reversibility: Low to medium.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The third layer is the one that separates the architect’s perspective from the CTO’s. An architect evaluating a proposed system design asks: is this scalable, is it secure, is it the right structure for the product we are building? These are the right questions for layer two. But the CTO has to put on a different cap and ask a different set of questions about the same decision: can we actually deliver this, on what timeline, with what team? And once it is in production — can we support it, debug it, explain it to a customer when something goes wrong?&lt;/p&gt;

&lt;p&gt;These are not architectural questions. They are operational ones. And they belong at their own layer because they are evaluated against entirely different criteria, and because getting them wrong produces entirely different consequences from getting layer two wrong.&lt;/p&gt;

&lt;p&gt;The technology stack decision lives here more than it lives at layer two. A CTO choosing between technology options is not primarily making an architectural choice — the architecture can often be expressed in multiple stacks equally well. They are making an operational and delivery choice: which stack allows the team to move at the speed the business requires? Which stack is supportable with the team that exists, and the talent that can be hired? Which stack is legible enough to an AI agent that the team can leverage AI assistance across the full delivery cycle — from initial development through to production support?&lt;/p&gt;

&lt;p&gt;This last criterion is newer but increasingly decisive. A stack with deep AI tooling support — where the language, the ecosystem, and the common patterns are well-represented in AI training data — compresses delivery timelines in ways that a technically superior but AI-opaque stack cannot match. The choice of Python over Java for a given system may be architecturally neutral. Operationally, in a world where AI agents are doing a meaningful fraction of the implementation and support work, it is not neutral at all.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The CTO who evaluates a technology choice purely on architectural merit is answering the right question at the wrong layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The questions that belong here: how long will it take to deliver the first version, and the tenth version, with this stack and this team? When something breaks in production at 2am, how quickly can the on-call engineer understand what went wrong and why? Can an AI agent navigate this codebase reliably enough to assist with debugging, with code review, with generating test coverage? What is the support burden this technology choice places on the team — and is that burden sustainable at the scale the product needs to reach?&lt;/p&gt;

&lt;p&gt;The failure mode at this layer is invisible to architects and visible to everyone else. An architecture that is technically correct but operationally brutal produces delivery timelines that look like team performance problems, support burdens that look like reliability problems, and attrition that looks like culture problems. None of these are the root cause. The root cause is a layer-three decision that was never made explicitly — because it was evaluated at layer two, against layer-two criteria, by people whose job is layer two.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-4-engineering-organization&quot;&gt;Layer 4: Engineering Organization&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Quarters to years. Reversibility: Medium.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fourth layer is organizational: how is the engineering team structured, how is ownership assigned, how do teams coordinate, how are decisions made, how does the organization scale.&lt;/p&gt;

&lt;p&gt;This layer is where the stack’s interactions become most consequential — because the engineering organization is the mechanism through which all other layers are realized. The best architecture is worthless if the organization cannot build it. The most operationally sound technology choice is worthless if the team structure creates coordination overhead that cancels out its delivery advantages. The most thoughtful infrastructure is worthless if the teams responsible for it do not have the context to operate it.&lt;/p&gt;

&lt;p&gt;Conway’s Law is not an observation about technology. It is an observation about this layer.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not a historical curiosity. It is an active constraint on every architecture decision made at layer two. Teams build what they can communicate about. Boundaries emerge where communication is expensive. The architecture of the product reflects the topology of the organization that built it — and if those two things are not deliberately aligned, they will be accidentally misaligned in ways that compound over time.&lt;/p&gt;

&lt;p&gt;The implication is directional: the engineering organization needs to be structured around the product architecture, not the other way around. This is harder than it sounds. Most organizations have existing team structures, existing reporting lines, existing ownership patterns. Changing them is slow and politically costly. The temptation is to fit the architecture to the org rather than the org to the architecture — and this temptation, consistently indulged, is how products become unmaintainable.&lt;/p&gt;

&lt;p&gt;The failure mode at this layer is not structural incorrectness. It is structural lag — the organization that was correct for the product at one stage and has not been deliberately redesigned for the next stage. Teams that made sense when the product was a monolith but create friction now that it is decomposed. Ownership models that worked when the team was twenty people but break at a hundred. Coordination patterns that were fine for one product surface but add unbearable overhead now that there are three.&lt;/p&gt;

&lt;p&gt;The questions that belong here: does team structure match the system’s architecture — or is it creating architectural pressure the system cannot absorb? Where are the coordination bottlenecks — and are they in the team structure, the ownership model, or the architecture? Is ownership of each component clear enough that the people responsible for it have the context to make good decisions about it?&lt;/p&gt;

&lt;p&gt;Amazon’s two-pizza team rule is the most cited example of a layer-four decision — and one of the most misunderstood. The rule was not primarily about team size. It was about ownership. A team small enough to be fed by two pizzas is a team small enough to fully own a component: to understand its behavior under load, to be on call for it, to make architectural decisions about it without requiring coordination with another team. The size constraint was a proxy for the ownership constraint. Organizations that adopted the rule without adopting the ownership model got small teams with diffuse responsibility — which is worse than large teams with clear ownership, because the diffusion is harder to see.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-5-people--talent&quot;&gt;Layer 5: People &amp;amp; Talent&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Quarters to years. Reversibility: Medium.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fifth layer is people: who is on the team, what capabilities they have, how they are developed, and — increasingly — how the boundary between human engineers and AI agents is governed.&lt;/p&gt;

&lt;p&gt;This layer is distinct from the engineering organization layer above it. Layer four is about structure — how teams are arranged, how ownership is assigned, how coordination happens. Layer five is about the humans and agents within that structure — their skills, their composition, their development, and the governance model that determines how human judgment and AI capability are combined.&lt;/p&gt;

&lt;p&gt;For most of the history of software engineering, the people layer was primarily a hiring and retention problem: recruit engineers with the right skills, keep them engaged, develop them over time. These concerns remain real. But the arrival of capable AI agents has added a dimension that most organizations have not yet explicitly addressed: the engineering team is no longer purely human, and the decisions about how to compose, govern, and quality-control a hybrid team are not being made at this layer — they are being made ad hoc, at layer seven, by individual engineers choosing which tasks to delegate to an agent and which to handle themselves.&lt;/p&gt;

&lt;p&gt;That is the wrong layer for those decisions.&lt;/p&gt;

&lt;p&gt;The questions that belong at layer five: what is the right composition of human engineers and AI agents for the work this organization needs to do? Which categories of work should remain primarily human — because they require judgment, accountability, or contextual understanding that agents cannot reliably provide — and which can be reliably delegated? What does quality control look like when a significant fraction of the codebase is agent-generated? How is accountability assigned for agent output — who owns it, who reviews it, who is responsible when it fails?&lt;/p&gt;

&lt;p&gt;Governance of the human-agent boundary is the defining people challenge of this moment in software engineering. Organizations that have not made explicit decisions at this layer are making implicit ones — usually in the direction of maximum agent adoption at minimum governance, which produces speed in the short term and fragility in the medium term. Code that nobody fully understands, test coverage that was generated rather than reasoned about, architectural decisions embedded in agent output that no human reviewed as architectural decisions.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The question is not whether to use AI agents. It is who is responsible for what they produce — and whether that responsibility is explicit enough to be exercised.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The questions that belong here also include the development of human engineers in an AI-augmented environment. The skills that are most valuable are shifting: from implementation fluency toward specification precision, from code authorship toward architectural judgment, from debugging skill toward the ability to evaluate agent output critically. An organization that is not deliberately developing these capabilities in its human engineers is building a team that is increasingly dependent on agents it does not fully understand and cannot fully supervise.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-6-infrastructure&quot;&gt;Layer 6: Infrastructure&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Months. Reversibility: Medium to high.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sixth layer is infrastructure: cloud platform, data platform, networking, security posture, deployment model, observability stack.&lt;/p&gt;

&lt;p&gt;This is the layer that generates the most tactical urgency. Infrastructure decisions carry immediate cost implications, immediate reliability implications, and immediate operational overhead. They are also, among the seven layers, among the most frequently conflated with strategic decisions — because the vendors selling infrastructure services have a strong incentive to frame them that way.&lt;/p&gt;

&lt;p&gt;They are not strategic decisions. They are structural ones.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Infrastructure is not a strategy. It is the physical expression of an architecture. The choice of database engine is not a business bet. The choice of whether to own your data layer is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The correct frame for infrastructure decisions is: does this choice give the architecture what it needs to deliver the product the business requires, at a cost structure the business can sustain, with an operational burden the organization can carry?&lt;/p&gt;

&lt;p&gt;Notice what is not in that frame: vendor preference, engineer familiarity, and what competitors are using. These are inputs, not criteria. An infrastructure choice that satisfies the frame is a good one even if it is boring. An infrastructure choice that fails the frame is a bad one even if it is technically elegant.&lt;/p&gt;

&lt;p&gt;The specific failure that is most expensive is infrastructure lock-in masquerading as a platform bet. Choosing a cloud provider is a reversible decision — painful and expensive to reverse, but possible. Choosing a cloud provider and then building every product capability directly on top of provider-specific services, without abstraction, makes the decision effectively irreversible. This is sometimes the right tradeoff. It is almost never made explicitly.&lt;/p&gt;

&lt;p&gt;Dropbox’s decision to migrate off AWS and build its own storage infrastructure — Magic Pocket — is one of the few examples of a layer-six decision made with full layer-one and layer-two visibility. At Dropbox’s scale, storage was the primary cost driver of the business, and the cost curve of managed cloud storage made the unit economics increasingly difficult. The infrastructure decision was downstream of a business strategy question: can this company survive long-term on managed storage costs, or does it need to own the infrastructure to own the margin? Reaching that answer required the CTO to connect infrastructure economics to business strategy — not to evaluate the migration as a purely technical question.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;layer-7-developer-productivity&quot;&gt;Layer 7: Developer Productivity&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time horizon: Weeks to months. Reversibility: High.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The seventh layer is developer productivity: the tooling, processes, practices, and environment in which engineers work day to day. Build systems, local development environments, CI/CD pipelines, code review processes, deployment tooling, testing infrastructure, documentation practices.&lt;/p&gt;

&lt;p&gt;This is the layer that is most frequently mismanaged in two opposite directions.&lt;/p&gt;

&lt;p&gt;The first direction is neglect. Engineering leadership treats developer productivity as a maintenance concern rather than a strategic investment, defers improvements indefinitely under delivery pressure, and ends up with a development environment that is slow, fragile, and frustrating — which produces exactly the delivery pressure that supposedly justified not investing in it.&lt;/p&gt;

&lt;p&gt;The second direction is over-investment. Engineering leadership treats developer productivity as the primary lever for organizational performance, invests heavily in tooling sophistication and process refinement, and ends up with a beautifully instrumented development environment that is building the wrong product efficiently.&lt;/p&gt;

&lt;p&gt;Neither direction understands what this layer is actually for.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Developer productivity tooling is not about making engineers faster. It is about making the architecture legible to the people building it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A well-instrumented CI pipeline that surfaces architectural violations is valuable not because it speeds up deployment but because it enforces the architectural contracts that the product’s integrity depends on. A local development environment that accurately mirrors production is valuable not because it improves individual productivity but because it reduces the gap between where decisions are made and where their consequences are visible. A test suite with genuine boundary coverage is valuable not because it speeds up delivery but because it is the mechanism by which architectural changes can be validated as safe.&lt;/p&gt;

&lt;p&gt;Google’s internal developer tooling — Blaze, Critique, Piper — is the most extreme version of layer-seven investment in the industry, and it illustrates both the ceiling and the precondition. Google spent years and significant engineering resources building tools tightly coupled to its monorepo architecture. The productivity investment was real. But it only paid off because it was designed specifically around Google’s architectural choices. Teams that cargo-culted the tools without the architecture got the complexity without the benefit. The lesson is not that developer tooling investment is always worth it. It is that tooling investment is only worth it when it is directly expressive of the architecture it serves.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-the-layers-break-down&quot;&gt;How the Layers Break Down&lt;/h2&gt;

&lt;p&gt;The stack is a decision-making framework, not a delegation model. All seven layers require the CTO’s attention. The question is not which layers the CTO works in — it is whether the decisions being made in each layer are being evaluated against the right criteria.&lt;/p&gt;

&lt;p&gt;Three breakdown patterns appear consistently across engineering organizations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategic decisions masquerading as technical ones.&lt;/strong&gt; A platform migration evaluated purely on technical merit. A build-vs-buy decision evaluated on feature parity rather than organizational capability. A vendor selection evaluated on performance benchmarks rather than cost structure at scale. A technology stack choice evaluated on architectural elegance rather than operational deliverability and support burden. In each case, a decision that belongs at layer one, two, or three is being made with layer six or seven criteria — and the consequences accumulate upward invisibly until they become a business problem rather than a technical one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical decisions resolved at the wrong layer.&lt;/strong&gt; An infrastructure choice that constrains the product architecture, made without awareness of the constraint. An organizational structure that calcifies around a system design that has since changed. A developer productivity investment that optimizes for the current team structure rather than the target architecture. An AI adoption decision made at the tooling layer without reference to the governance model it requires at the people layer. In each case, a decision at one layer is made without visibility into its implications for adjacent layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer collapse under pressure.&lt;/strong&gt; When organizations are under delivery pressure, the stack compresses. Strategic and architectural decisions get deferred in favor of operational ones. Technology choices get made by whoever is closest to the implementation, evaluated against implementation criteria. The organizational structure remains frozen while the architecture evolves around it. The people layer never gets explicitly designed — it accumulates by default. The collapse is not visible as a failure at the time — it looks like pragmatism, like keeping things moving. The debt it creates becomes visible later, when the organization discovers that it cannot make a particular architectural change because the organizational structure is in the way, or that it cannot pursue a strategic direction because an infrastructure choice made two years ago has made it prohibitively expensive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cto-decision-stack/breakdown-patterns.svg&quot; alt=&quot;Breakdown Patterns&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-note-on-ai&quot;&gt;A Note on AI&lt;/h2&gt;

&lt;p&gt;AI does not belong to a single layer of the stack.&lt;/p&gt;

&lt;p&gt;Most organizations experience it first at layer seven — developer tooling, coding assistants, CI integration. But its consequences reach all the way up: to how teams are governed at layer five, to how technology is selected at layer three, to how architecture is designed at layer two, and ultimately to what kind of company this organization can credibly be at layer one.&lt;/p&gt;

&lt;p&gt;Treating AI as a tooling decision is often the first and most visible example of layer collapse. The full implications of AI across each layer of the stack deserve a separate treatment — and that is where this series goes next.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-stack-in-context&quot;&gt;The Stack in Context&lt;/h2&gt;

&lt;p&gt;The seven layers are constant. What varies is how they behave depending on organizational context — and the variation is large enough to warrant its own treatment.&lt;/p&gt;

&lt;p&gt;The short version: the startup’s primary risk at each layer is invisibility — decisions being made without awareness that a layer exists. The enterprise’s primary risk is disconnection — layers operating without awareness of each other.&lt;/p&gt;

&lt;p&gt;Both risks produce the same outcome: decisions made at the wrong layer, evaluated against the wrong criteria, with consequences that arrive later and look like a different problem than the one that caused them. How each context produces that outcome, and what to do about it, is where this series goes after AI.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;using-the-stack&quot;&gt;Using the Stack&lt;/h2&gt;

&lt;p&gt;The decision stack is not a process. It does not tell you what to decide. It tells you where a decision belongs — which changes how it is evaluated, who should be in the room, and what counts as a good outcome.&lt;/p&gt;

&lt;p&gt;The diagnostic is simple. For any significant decision the engineering organization is facing, ask: what layer does this decision actually live in? Then ask: is it being evaluated at that layer?&lt;/p&gt;

&lt;p&gt;If a technology stack choice is being evaluated on architectural elegance rather than delivery speed, support burden, and AI fluency, it is being evaluated at the wrong layer — layer two criteria applied to a layer three decision. If a decision about organizational structure is being made without reference to the architectural boundaries the organization needs to maintain, it is being made at the wrong layer. If a decision about cloud vendor is being made as a strategic bet when it should be evaluated as an infrastructure tradeoff, it is being framed at the wrong layer. If decisions about AI agent governance are being made by individual engineers at the tooling layer rather than explicitly at the people layer, they are being resolved three layers below where they belong.&lt;/p&gt;

&lt;p&gt;Most of the time, the problem is not the decision. It is the frame.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The CTO’s job is not to make decisions. It is to make sure decisions are made at the layer they actually belong to — with the right information, the right people, and the right criteria.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The stack also provides a map for communication. Different stakeholders in an organization have visibility into different layers. Engineers have the deepest visibility into layers six and seven. Product managers have the clearest view of layer two’s requirements. HR owns parts of layer five without owning the layer. The executive team lives in layer one. The CTO is the only person in the organization whose job requires fluency across all seven levels — and whose value comes precisely from the ability to translate between them: to carry the implications of a strategic decision downward into infrastructure choices, and to surface the implications of an operational constraint upward into product and business conversations.&lt;/p&gt;

&lt;p&gt;Most technology failures are not failures of architecture, infrastructure, tooling, or people.
They are failures of framing.&lt;/p&gt;

&lt;p&gt;Decisions made at the wrong layer eventually create consequences that appear somewhere else — and look like a different problem than the one that caused them.&lt;/p&gt;

&lt;p&gt;The CTO Decision Stack exists to make those layers visible before the consequences arrive.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Ali Ahmed Thawerani writes about the systems, culture, and scale decisions that shape how technology organisations develop. TECTONICS publishes at &lt;a href=&quot;https://aathawerani.github.io&quot;&gt;aathawerani.github.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 07 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/2026/06/07/cto-decision-stack/</guid>
      </item>
    
      <item>
        <title>Tech Stack Selection in the Age of AI Agents</title>
        <description>&lt;h2 id=&quot;a-third-variable&quot;&gt;A Third Variable&lt;/h2&gt;

&lt;p&gt;Historically, stack selection was driven by two things: the problem domain and the team’s existing expertise. Both remain relevant. But there is now a third variable that most teams are not accounting for explicitly.&lt;/p&gt;

&lt;p&gt;The AI agent writing the code has strong opinions about what it can build well — and those opinions do not always align with what would be optimal for the domain.&lt;/p&gt;

&lt;p&gt;AI coding capability is not uniform across stacks. It is ecosystem-relative.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An AI agent is not simply a language model applied to a codebase. It is a language model whose suggestions are calibrated to the density and quality of training examples it has seen — and that density varies enormously across stacks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/tech-stack-ai-agents/ai_stack_confidence_spectrum.svg&quot; alt=&quot;AI stack confidence spectrum&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Python dominates that distribution. An AI agent generating FastAPI route handlers, SQLAlchemy models, Pydantic schemas, and Alembic migrations is not just producing correct Python. It is producing &lt;em&gt;idiomatic&lt;/em&gt; Python — the specific patterns and library combinations that the ecosystem has converged on over years of collective practice. That is qualitatively different from an AI that knows the syntax but not which library to reach for, which patterns are now antipatterns, or which dependency combinations cause subtle production issues.&lt;/p&gt;

&lt;p&gt;Vite and React sit in the same high-confidence tier on the frontend. The AI is operating close to the centre of its training distribution: component structure, state management patterns, API integration conventions — all rendered with high reliability.&lt;/p&gt;

&lt;p&gt;This has a practical implication that is worth stating directly: your stack choice is also, implicitly, a choice about what kind of AI partner you will have for the next six months. The students at Habib University’s Kaavish exhibition who built Python + Vite prototypes were not making a conservative choice. They were making a strategically correct one — working where the tools are strongest rather than where the theory is most elegant.&lt;/p&gt;

&lt;p&gt;There is a further dimension to this that the AI fluency argument alone does not capture: Python and TypeScript are also globally the most hireable stacks, with the deepest tutorial ecosystems, the largest communities, and the most abundant open-source examples. When a new engineer joins the team, onboarding them onto idiomatic FastAPI or React is weeks faster than onboarding them onto a niche framework with thin documentation. The AI and the hiring market are pointing in the same direction. That alignment is not a coincidence — both are responding to the same underlying signal about where collective expertise has concentrated.&lt;/p&gt;

&lt;p&gt;Go, Rust, and Kotlin sit at an intermediate layer — well-represented for common patterns but with more variance at the edges. The further you move from the high-confidence core, the more the AI shifts from an asset into a liability — not useless, but less consistent in ways that compound.&lt;/p&gt;

&lt;p&gt;The stack choice is the first architectural decision. It is also the decision that determines how much leverage everything else provides.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;build-only-the-usp-buy-everything-else&quot;&gt;Build Only the USP. Buy Everything Else.&lt;/h2&gt;

&lt;p&gt;Speed at prototype stage comes from a simple principle: build only what makes your product worth using, and buy everything else.&lt;/p&gt;

&lt;p&gt;Every software product has to solve a class of problems that have nothing to do with why users would choose it over an alternative. Authentication, file storage, email delivery, SMS, database hosting, queuing, monitoring — none of these are why a logistics product wins customers. No fintech product earns its market position because it built a better password reset flow. These are cross-cutting concerns: genuinely hard problems that every product has, solved reliably by specialised providers, with no competitive advantage to be gained from building them from scratch.&lt;/p&gt;

&lt;p&gt;A second category sits just beyond: domain-specific commodity services. Payments via Stripe. Maps via Google Maps or Mapbox. Identity verification via a KYC provider. These feel like core functionality because they are domain-specific — but they are common enough across the domain that mature solutions already exist. A fintech prototype does not need to build its own payment processing. A logistics prototype does not need to build its own geocoding.&lt;/p&gt;

&lt;p&gt;What remains after removing both categories is the core business value — the unique insight, the differentiated workflow, the algorithm or data model that is the actual reason the product should exist. This is the only thing worth building from scratch. This is what the prototype validates.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/tech-stack-ai-agents/buy_vs_build_zones.svg&quot; alt=&quot;Buy vs build zones&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cost curve will shift.&lt;/strong&gt; As the product scales, what was negligible becomes significant. The economics of self-hosting gradually improve relative to the managed service cost — a pattern documented across software organisations at growth stage. When that crossover arrives, the managed service should be replaceable without touching the rest of the system.&lt;/p&gt;

&lt;p&gt;That is only true if every managed service sits behind one interface file from day one. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auth/provider.py&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage/provider.py&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notifications/provider.py&lt;/code&gt;. When Supabase Auth’s pricing model changes at scale, the migration scope is one file. When email volume justifies a self-hosted mail server, the migration scope is one file. The rest of the codebase does not know and does not care.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Buy the cloud. Own the seam.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-architecture-of-the-prototype-that-survives&quot;&gt;The Architecture of the Prototype That Survives&lt;/h2&gt;

&lt;p&gt;The prototype built with speed but no structural discipline tends to become the thing that blocks future progress — not because it failed, but because it succeeded. It is in production. Real users depend on it. And the choices that were fine for a learning exercise are now structural problems with no clean way out.&lt;/p&gt;

&lt;p&gt;The disciplines below are not overhead. Each takes an hour or a day at prototype stage and saves weeks or months at migration stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organise by domain, not by technical layer.&lt;/strong&gt; An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;orders/&lt;/code&gt; module, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers/&lt;/code&gt; module, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payments/&lt;/code&gt; module — rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;models/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;routes/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;services/&lt;/code&gt; layers that scatter every feature across the whole codebase. The domain module is the unit of future extraction. Without it, there is no clean unit to extract.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manage the schema from the first table.&lt;/strong&gt; Use Alembic, Flyway, or Prisma Migrate from day one. The schema is the most expensive thing to change under real load. A migration history that starts at the first table is a foundation. A schema altered ad hoc is an archaeology problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrap every external dependency behind one interface file.&lt;/strong&gt; Every third-party service — auth provider, payment processor, storage, email — sits behind a single file all callers use. This is the one structural decision that keeps every future replacement bounded to one file and one scope of work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delegate authentication entirely.&lt;/strong&gt; Auth couples to the user model, the session model, and the permission model — all of which accumulate real data quickly. The prototype’s auth tends to become the production auth. Buying it from a provider is not a shortcut. It is the correct decision for the stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add structured logging with a correlation ID before you have users.&lt;/strong&gt; A JSON log event with a consistent shape, carrying a correlation ID that propagates through every downstream call, is almost free to add early and expensive to retrofit. It is also the specific precondition for safely validating a replacement service against real production traffic before switching over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run in containers from day one.&lt;/strong&gt; Docker forces enumeration of every dependency the system has — runtime version, system packages, environment variables. The result is a system that can be deployed anywhere and can host transitional infrastructure without environment drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate configuration from code.&lt;/strong&gt; Environment variables for all configuration. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env.example&lt;/code&gt; that documents what is required without values. The gap between staging and production configs, under go-live pressure, is where secrets get committed to version control.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/tech-stack-ai-agents/module_boundary_seam_diagram.svg&quot; alt=&quot;Module boundary seam diagram&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;test-the-boundaries-not-the-implementation&quot;&gt;Test the Boundaries, Not the Implementation&lt;/h2&gt;

&lt;p&gt;TDD has a reputation problem at prototype stage. Writing tests before code feels like overhead when learning speed is everything. The resolution is not to abandon testing — it is to be precise about what to test.&lt;/p&gt;

&lt;p&gt;Tests at prototype stage should cover boundaries, not implementation details. The internal workings of a module can be refactored freely as the domain is better understood. What cannot change without consequences is the contract a module exposes — the service interface between modules, the API contract between backend and frontend, the interface file wrapping an external vendor. These are the seams. The seams need tests. Everything else is optional until it proves itself worth testing.&lt;/p&gt;

&lt;p&gt;This connects directly to AI-assisted development in a specific way. Given a well-defined Pydantic schema and a service function signature, an AI generates meaningful boundary tests — happy paths, edge cases, error conditions — faster than a human. Given an unstructured codebase, the same AI generates tests tightly coupled to implementation details: tests that break on every refactor, produce false confidence, and eventually get deleted. The template precedes the tests. Boundary discipline is what makes AI-generated tests worth having.&lt;/p&gt;

&lt;p&gt;The tests that directly enable future migration are worth naming: a service interface test suite means that when you rewrite the implementation behind a module boundary — a new Go service, a self-hosted auth provider, a rewritten notification engine — you run the same tests against the new implementation and know immediately whether it behaves correctly. That is the confidence mechanism for safe replacement. Without it, every migration requires manual verification of every behaviour the old implementation had.&lt;/p&gt;

&lt;p&gt;One anti-pattern to name explicitly: testing the framework instead of the domain. Tests that verify FastAPI routing mechanics or SQLAlchemy query behaviour are testing things the libraries already guarantee. The valuable tests are on domain logic — does the order state machine transition correctly, does the pricing calculation handle the edge cases the business cares about. The framework can be trusted. The domain logic cannot.&lt;/p&gt;

&lt;p&gt;The practical starting point: one test file per module service interface, one per API endpoint group, one mock-based test per external dependency wrapper. That is the minimum that keeps migration options open.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-ui-gap-nobody-talks-about&quot;&gt;The UI Gap Nobody Talks About&lt;/h2&gt;

&lt;p&gt;There is a dimension missing from almost every architectural template written for early-stage products: the frontend.&lt;/p&gt;

&lt;p&gt;Backend architecture gets most of the attention. The frontend is treated as the presentation layer — a consequence of the real decisions, not a domain with its own architectural concerns. This is a mistake that becomes expensive exactly when the product starts to scale.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Frontend debt is cognitive rather than structural. Not coupling between modules or schema problems, but components that grew without boundaries, state in the wrong place, API calls inlined wherever first needed and then copied rather than centralised. The result is a frontend that resists change because there are no clean units to work with.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three rules prevent this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organise by feature, not by type.&lt;/strong&gt; A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt; folder containing both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Button&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderSummaryCard&lt;/code&gt; is not a components folder — it is a pile. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderSummaryCard&lt;/code&gt; contains business logic, depends on a specific data shape, and belongs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;features/orders/components/&lt;/code&gt;. Genuinely shared UI belongs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt;. Domain-specific code lives in its feature folder. This boundary is the frontend equivalent of the domain module.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src/
  features/
    orders/
      components/  # OrderList, OrderCard — orders-specific
      hooks/       # useOrders, useOrderStatus
      types.ts
    payments/
      components/
      hooks/
      types.ts
  components/      # Button, Modal, Input — shared, no business logic
  services/        # ALL API calls — never inline fetch in components
  hooks/           # shared hooks, no domain specificity
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Centralise all API calls in a services layer.&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/services/&lt;/code&gt; owns every external call — typed functions that speak the domain language (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getOrderById(id)&lt;/code&gt;, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get(&apos;/api/v1/orders/{id}&apos;)&lt;/code&gt;), with consistent error handling. The AI’s instinct is to put the fetch call where the data is first needed. A template that encodes the rule changes what the AI generates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer state management deliberately.&lt;/strong&gt; Server state — data from the API — belongs in TanStack Query. It has its own caching and invalidation semantics that a global store does not handle well. UI state belongs at the component or feature level. Only genuinely global state — current user, authentication — belongs in a global store. Without this in the template, the AI reaches for the global store for everything.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;encoding-it-all-in-a-template&quot;&gt;Encoding It All in a Template&lt;/h2&gt;

&lt;p&gt;The disciplines above — domain modules, schema migrations, interface files, boundary tests, feature-based frontend structure — are the decisions that need to be made before the first line of code is written. Left unencoded, each one will be reinvented inconsistently across sessions as the AI fills the gaps with whatever seemed convenient at the moment.&lt;/p&gt;

&lt;p&gt;The previous post in this series argued that architecture is shifting from diagrams to guardrails — from documentation that describes intent to constraints that enforce it. The practical form of that at prototype stage is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; at the root of the repository: not a prompt, but an architecture. Every rule in the file is implicitly an ADR — a decision with a rationale that future engineers and AI agents can read rather than re-derive.&lt;/p&gt;

&lt;p&gt;A minimal template for a Python + Vite stack, encoding everything covered above:&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gh&quot;&gt;# Architecture Template&lt;/span&gt;

&lt;span class=&quot;gu&quot;&gt;## Stack&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; Backend: Python 3.12, FastAPI, SQLAlchemy 2.0, Alembic, Pydantic v2
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; Frontend: Vite, React 18, TypeScript, TanStack Query
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; Auth: Supabase Auth — never implement custom auth
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; Database: PostgreSQL — all schema changes via Alembic migrations only

&lt;span class=&quot;gu&quot;&gt;## Backend Module Structure&lt;/span&gt;
Organise by domain, not by technical layer.

src/
  auth/          # authentication, session management
  users/         # user profiles, preferences
  orders/        # order lifecycle
  payments/      # payment processing
  notifications/ # outbound communication

Each module: models.py, schemas.py, service.py, router.py
No cross-module imports except through explicit service interfaces.

&lt;span class=&quot;gu&quot;&gt;## External Dependency Rule&lt;/span&gt;
Every third-party service behind one interface file.
src/payments/provider.py      — all Stripe calls go here, nowhere else.
src/notifications/provider.py — all SendGrid calls go here, nowhere else.

&lt;span class=&quot;gu&quot;&gt;## Schema Management&lt;/span&gt;
Every database change through an Alembic migration. Never ALTER TABLE manually.

&lt;span class=&quot;gu&quot;&gt;## Logging&lt;/span&gt;
Structured JSON via structlog. Every request carries a correlation_id.

&lt;span class=&quot;gu&quot;&gt;## Configuration&lt;/span&gt;
All config via environment variables. No hardcoded credentials.
.env.example documents required variables without values.

&lt;span class=&quot;gu&quot;&gt;## Frontend Structure&lt;/span&gt;
src/
  features/    # one folder per domain (orders/, payments/, users/)
  components/  # shared UI only — no business logic, no API calls
  services/    # ALL API calls here — never inline fetch in components
  hooks/       # shared hooks only

&lt;span class=&quot;gu&quot;&gt;## Testing&lt;/span&gt;
One test file per module service interface.
One test file per API endpoint group.
One mock-based test per external dependency wrapper.
Test domain logic, not framework mechanics.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file is written once. From that point, the AI follows it — not because it has judgment, but because it has instructions. The judgment was applied once, by a human, at the start.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;designing-for-replaceability&quot;&gt;Designing for Replaceability&lt;/h2&gt;

&lt;p&gt;Here is what connects every discipline above to the long-term arc of the product: the patterns used to migrate a system to enterprise grade each have a precondition, and those preconditions are exactly what good prototype architecture creates.&lt;/p&gt;

&lt;p&gt;Three structural choices — made once, at the start — keep every migration option available later. Miss them and the only path forward is a full rewrite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The seam is everything.&lt;/strong&gt; Michael Feathers called the natural split points in a codebase &lt;em&gt;seams&lt;/em&gt; — places where the system can be divided without modifying surrounding code. In a prototype, the domain module boundary is the seam. The Strangler Fig pattern — where new services are built alongside the old system and traffic is redirected one capability at a time — only works if a clean intercept point exists. The domain module, with its own router and service interface, is that intercept point. A codebase with no module boundaries has no seams. A codebase with no seams cannot be incrementally migrated. It can only be rewritten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The interface file is the abstraction that already exists.&lt;/strong&gt; Branch by Abstraction — for replacing a component deep inside the system — requires first introducing an abstraction and migrating all callers to use it. That is the expensive step. The external dependency interface file does this work at day zero. When the time comes to swap Stripe for a self-built payment service, or replace Supabase Auth with a self-hosted provider, the abstraction already exists and every caller already uses it. The same logic applies to cloud services: buying managed solutions behind interface files means the cost-curve replacement is always one file deep.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feature boundary is what makes UI migration possible.&lt;/strong&gt; Replacing a frontend section by section — while the rest continues running — requires that sections are independently identifiable and modifiable. In its coarser form, an entire page or user-type experience is the replacement unit: a new driver dashboard built as a separate application, calling the existing backend through its clean API surface, with traffic routing directing drivers to the new version while the customer experience is untouched. In its finer form, individual widgets within a page are replaced one at a time. Both require the feature-based frontend structure. A frontend where every domain’s code is scattered across shared folders requires untangling before it can be extended.&lt;/p&gt;

&lt;p&gt;Three further patterns follow from the remaining disciplines without requiring their own names. The migration-based schema enables making schema changes on a live system in phases — add the new structure alongside the old, migrate data, remove the old — each phase independently deployable and reversible, no maintenance window required. The correlation ID in structured logs enables running old and new implementations simultaneously on real traffic and comparing outputs before committing to the switch — the precondition being that you can match a request across both systems. And for multi-sided products, keeping each user type in its own vertical slice means one side can be migrated completely while the other continues on the original system.&lt;/p&gt;

&lt;p&gt;One anti-pattern deserves explicit naming: Feature Parity — the requirement that a replacement must reproduce every behaviour of the old system before any switch can happen. In the prototype-to-enterprise context this most often appears when a team takes over a solo-built prototype and treats every undocumented quirk as a feature to preserve. The correct target is outcome parity — the new implementation delivers the same results for users — not behavioural parity. Architecture Decision Records are the countermeasure: an ADR explaining why a workaround exists gives the replacement team permission to do better rather than obligation to replicate.&lt;/p&gt;

&lt;p&gt;What this collection of disciplines adds up to is something Neal Ford and Rebecca Parsons called &lt;em&gt;evolutionary architecture&lt;/em&gt; — systems designed to adapt through guided incremental change rather than periodic rewrites. The three mechanisms they identify map directly onto what the prototype disciplines create: appropriate coupling (domain module boundaries that let parts change independently), incremental change (deployable units small enough to be reversible, enabled by migration-based schemas and interface files), and fitness functions (the boundary test suite that verifies architectural properties — the interface contracts — hold after every change). The prototype built with these disciplines is not just easier to migrate. It is a system that can evolve continuously, absorbing change without accumulating the structural debt that eventually forces a rewrite. The migration patterns described above are not the destination. They are the evidence that the architecture is working as designed.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-the-prototype-disciplines-protect&quot;&gt;What the Prototype Disciplines Protect&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/tech-stack-ai-agents/disciplines_to_patterns_map.svg&quot; alt=&quot;Disciplines to patterns map&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The seam is the module boundary. Everything else follows from having drawn it deliberately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;domain-gravity-and-the-migration&quot;&gt;Domain Gravity and the Migration&lt;/h2&gt;

&lt;p&gt;The disciplines above address what survives from the prototype. They do not address whether the prototype’s stack is the right substrate for the product’s second and third years.&lt;/p&gt;

&lt;p&gt;Different domains have accumulated expertise and ecosystem depth in specific stacks, and that accumulation represents real leverage. Financial systems have decades of compliance tooling and institutional knowledge embedded in JVM ecosystems — Java and Kotlin won that domain not by preference but because the ecosystem was shaped by the actual demands of high-volume transaction processing and regulatory compliance. A fintech prototype that starts in Python should plan for the possibility that its transaction processing core will eventually need stronger type guarantees and richer compliance tooling.&lt;/p&gt;

&lt;p&gt;Real-time systems have their own gravitational pull towards strong concurrency models. Elixir and Erlang exist because the telecom industry needed fault tolerance that most languages could not deliver architecturally. A product that starts as a Python messaging layer and grows into a real-time communication platform will at some point encounter constraints inherent to Python’s concurrency model, not to any specific implementation choice.&lt;/p&gt;

&lt;p&gt;Machine learning has converged almost entirely on Python — not because it is fastest for numerical computation, but because the ecosystem of libraries, tooling, and practitioners is so concentrated there that building outside it means building without the compounding effect of that accumulated expertise. For ML-heavy products, Python is both the AI-fluent choice and the domain-correct choice. The prototype stack and the production stack are the same stack.&lt;/p&gt;

&lt;p&gt;The migration in each case is not a correction of the original choice. It is a natural stage in the product’s maturation — pulled by specific, observed constraints rather than pushed by theoretical elegance. The disciplines of the prototype stage are what make each migration a bounded step rather than a crisis.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-this-looks-like-end-to-end&quot;&gt;What This Looks Like End to End&lt;/h2&gt;

&lt;p&gt;A team building a two-sided logistics platform starts with Python + FastAPI + Vite + React. Before writing the first line of code, they create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; defining the module structure, dependency rules, vendor wrapping policy, logging format, and frontend organisation. The AI agent reads this as context on every task.&lt;/p&gt;

&lt;p&gt;The backend has domain modules: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;routes/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customers/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notifications/&lt;/code&gt;. Supabase Auth handles authentication. Stripe handles payments. Google Maps handles geocoding. Each external service sits behind one interface file. Alembic migrations from the first table. Docker from day one. Correlation IDs in structured JSON logs. An ADR written for every non-obvious decision. One test file per module service interface, one mock-based test per external dependency wrapper.&lt;/p&gt;

&lt;p&gt;The frontend has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;features/driver/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;features/customer/&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;features/ops/&lt;/code&gt;. All API calls through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/services/&lt;/code&gt;. TanStack Query for server state. TypeScript types for every API response shape.&lt;/p&gt;

&lt;p&gt;Six months later, twelve customers. The route optimisation engine takes eight seconds under load. The module boundary is already clean, the service interface already tested. A Go rewrite of that one module, validated against the existing test suite and confirmed with a parallel run on real traffic, takes three weeks. The rest of the system is untouched.&lt;/p&gt;

&lt;p&gt;A year later, the driver experience needs a complete redesign. UI Composition: a new driver application built separately, calling the existing FastAPI backend through its clean API surface. The routing layer sends driver traffic to the new application. The customer experience is untouched.&lt;/p&gt;

&lt;p&gt;Eighteen months in, expansion to a new market with compliance requirements that affect the customer product only. Extract Product Lines: the customer-facing backend migrates to a new stack with the required tooling. The driver product continues on the original system. The vertical slice discipline makes the boundary clean enough to migrate independently.&lt;/p&gt;

&lt;p&gt;Two years in, real-time tracking volume exposes Python’s concurrency limits. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tracking/&lt;/code&gt; module migrates to Elixir. Expand/Contract handles the schema migration without a maintenance window. The rest of the system does not change.&lt;/p&gt;

&lt;p&gt;At no point was the original choice treated as permanent. At no point was anything rewritten for its own sake. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; written before the first commit is the reason each migration remained a bounded step rather than a crisis.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/tech-stack-ai-agents/prototype_to_enterprise_timeline.svg&quot; alt=&quot;Prototype to enterprise timeline&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-right-stack-at-the-wrong-stage&quot;&gt;The Right Stack at the Wrong Stage&lt;/h2&gt;

&lt;p&gt;The stack does not exist in isolation. It is part of a system that includes the team building on it, the AI tools assisting with that building, the domain it is solving problems in, and the stage of the product’s life.&lt;/p&gt;

&lt;p&gt;The architecture template connects all these dimensions. It encodes the stack, the structural rules, and the conventions that give the AI a consistent context to work within. It also — as a byproduct of genuine discipline rather than premature optimisation — encodes the preconditions for the migration options that will be needed later.&lt;/p&gt;

&lt;p&gt;The right stack at the wrong stage is a wrong choice. The wrong stack, built with the right disciplines, can still get you to the point where you can make a better decision — with real data, real constraints, and a codebase structured to support the change.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The right stack at the wrong stage is a wrong choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is what separates products that compound from products that get stuck.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Ali Ahmed Thawerani writes about the systems, culture, and scale decisions that shape how technology organisations develop. TECTONICS publishes at &lt;a href=&quot;https://aathawerani.github.io&quot;&gt;aathawerani.github.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
        <pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/scale/2026/05/27/tech-stack-ai-agents/</guid>
      </item>
    
      <item>
        <title>From Project to Product to Company — What the Transition Actually Requires</title>
        <description>&lt;h2 id=&quot;from-final-year-project-to-startup&quot;&gt;From Final Year Project to Startup&lt;/h2&gt;

&lt;p&gt;I spent part of today as a juror at Habib University’s Kaavish - final year project exhibition — walking out, I kept thinking about one thing.&lt;/p&gt;

&lt;p&gt;How many of the projects I evaluated today are closer to a real business than their builders realise.&lt;/p&gt;

&lt;p&gt;In a structural sense the foundations were solid. The problem domains were understood at a depth that only sustained engagement produces. The students had spent a year being accountable to real stakeholders — not a professor marking a rubric, but an organisation that actually cared whether the solution worked.&lt;/p&gt;

&lt;p&gt;That kind of accountability is rare. It is also, not coincidentally, exactly what building a company feels like.&lt;/p&gt;

&lt;p&gt;What follows is not an evaluation of what was built. It is an attempt to describe what the next step looks like — and why more students should be taking it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-the-industry-already-knows&quot;&gt;What the Industry Already Knows&lt;/h2&gt;

&lt;p&gt;There is a reason companies invest in these programmes.&lt;/p&gt;

&lt;p&gt;Industry partners who supervise final year projects are making a calculated observation: the students who spend a year solving a real problem, with real constraints, in a real organisational context, come out the other side with something that cannot be hired in through a job posting. They have domain depth. They have the scar tissue of a project that did not go exactly as planned. They have the experience of defending a position under pressure to people who are not obligated to be kind about it.&lt;/p&gt;

&lt;p&gt;That is a foundation. The question that does not get asked enough — by the students themselves — is what to build on it.&lt;/p&gt;

&lt;p&gt;The job market is one answer. It is not the only one. And for the students who spent a year genuinely caring about the problem they were solving, it may not even be the most interesting one.&lt;/p&gt;

&lt;p&gt;Building your own thing is harder. It is also, if the problem is real and the understanding is deep enough, where the compounding begins. A job gives you a salary. A product built on genuine insight into a real problem gives you something that can outlast any single employer.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-pattern-worth-noticing&quot;&gt;The Pattern Worth Noticing&lt;/h2&gt;

&lt;p&gt;The most consequential technology companies tend to start the same way — not with a unique idea, but with an unusually deep understanding of a specific problem, and the decision to take that understanding seriously.&lt;/p&gt;

&lt;p&gt;Sualeh Asif grew up in Karachi and went on to MIT. While still a student there, he and three classmates built Cursor — an AI-powered coding environment — because they were frustrated with the tools developers already had. They made the problem personal before they made it a company. Cursor grew into one of the fastest-growing AI startups in recent memory, a valuation that places it among the most valuable developer tools companies in the world. Sualeh is 26.&lt;/p&gt;

&lt;p&gt;Aaqib Gadit built Cloudways in Pakistan — a managed cloud hosting platform that made enterprise-grade infrastructure accessible to small businesses who could not afford the complexity that came with it. He focused on one problem, solved it with unusual care, and stayed close enough to his users to keep understanding what they actually needed. DigitalOcean eventually acquired Cloudways.&lt;/p&gt;

&lt;p&gt;Neither of these started with an original idea. Both started with an unusually honest understanding of a specific problem — and the decision to stay with it long enough for that understanding to compound into something real.&lt;/p&gt;

&lt;p&gt;That same starting point exists for many of the projects being built in universities right now.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-space-is-never-empty-that-is-not-the-problem&quot;&gt;The Space Is Never Empty. That Is Not the Problem.&lt;/h2&gt;

&lt;p&gt;Here is the assumption that trips up more early-stage projects than any technical challenge: that a good idea needs an empty space to exist in.&lt;/p&gt;

&lt;p&gt;It does not. The space is never empty. Every problem worth solving already has someone working on it. The question is not whether competition exists. It is whether you understand your specific user well enough to find the detail that nobody else has handled yet.&lt;/p&gt;

&lt;p&gt;Simon Sinek’s framing is useful here, though not in the way it usually gets applied. Start With Why is not about mission statements. It is about the prior question: why would a specific person choose your solution over what already exists? If you cannot answer that for one real person in one real situation, you do not yet have enough information to make good decisions about what to build.&lt;/p&gt;

&lt;p&gt;Consider Bykea. It entered Pakistan’s ride-hailing market when Uber and Careem were already well established. Rather than competing on the same terms, it identified a specific user the existing platforms were not designed for — someone navigating dense urban traffic, needing an affordable short-distance ride, for whom a motorcycle was faster and cheaper than a car. That specificity was not a limitation. It was the entire strategy. Bykea did not try to serve everyone. It chose one user, understood that user’s actual day, and built around what that day required.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-need-behind-the-need&quot;&gt;The Need Behind the Need&lt;/h2&gt;

&lt;p&gt;There is a further distinction worth making — between the problem a user will tell you they have and the problem that is actually costing them.&lt;/p&gt;

&lt;p&gt;Users are good at describing symptoms. They are less reliable at diagnosing the underlying cause, because they have often adapted around it so completely that it no longer registers as a problem. It has become the way things are. The friction has been normalised. The workaround has become the workflow.&lt;/p&gt;

&lt;p&gt;The most valuable products are rarely built on the problem users articulate. They are built on the problem that reveals itself only when someone pays close enough attention to how things actually work — not how they are supposed to work, not how the user describes them working, but what actually happens when a real person attempts to do a real thing in a real environment.&lt;/p&gt;

&lt;p&gt;Careem did not discover that cash payments were necessary because someone asked for them. They discovered it because someone tried to pay with a card and could not. That moment — observed closely enough to be acted on — is where the insight came from. The same goes for building their own mapping system in a region where reliable street addresses did not consistently exist. Nobody filed a complaint about street addresses. The problem revealed itself only to someone paying close enough attention to how the experience actually worked. The need was always there. It took someone living close enough to it to see it.&lt;/p&gt;

&lt;p&gt;This is what sustained engagement with a problem produces that no survey or user interview can replicate. The hidden need. The friction so embedded in the experience that the person experiencing it has stopped seeing it as friction. Finding that detail — and building something that addresses it — is where the most durable differentiation lives.&lt;/p&gt;

&lt;p&gt;The students who spent a year embedded in a real domain, working alongside real organisations, have been closer to that kind of observation than most. The question is whether they were paying attention to it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-a-company-cares-about-that-a-demo-does-not-have-to&quot;&gt;What a Company Cares About That a Demo Does Not Have To&lt;/h2&gt;

&lt;p&gt;A demo proves something can work. A company proves it keeps working — when the data looks different from what was expected, when users approach the problem from angles the design did not anticipate, when the conditions that felt stable turn out to be in motion.&lt;/p&gt;

&lt;p&gt;The companies that endure are not the ones that predicted every change. They are the ones that built mechanisms to detect and respond to change as it happened. That distinction is structural. It is also designable — but only if it is thought about before the system is deployed, not after the first failure.&lt;/p&gt;

&lt;p&gt;When inDrive entered Pakistan’s ride-hailing market, Uber and Careem were already established. Its core insight was not technical — it was structural. Instead of fixing prices algorithmically, inDrive let passengers and drivers negotiate directly.&lt;/p&gt;

&lt;p&gt;That decision turned pricing into a feedback loop. Each ride became a data point — not captured after the fact, but embedded in the transaction itself. The market was not being predicted. It was being expressed.&lt;/p&gt;

&lt;p&gt;That is why the model worked. It did not assume it knew the right answer. It created a mechanism for the right answer to emerge. Careem subsequently launched its own negotiation feature in direct response — the clearest possible signal that the late entrant had found something the market had been waiting for.&lt;/p&gt;

&lt;p&gt;This is what a feedback loop means in a product context. Not ratings collected after the experience, but a system where real usage continuously shapes what happens next. The mechanism does not have to be complex. It has to be deliberate — designed in from the beginning, not added after the fact.&lt;/p&gt;

&lt;p&gt;That deliberateness is what separates products that compound from products that stagnate. And it is as applicable to an AI pipeline as it is to a pricing model. Which is where the next section begins.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;ai-is-the-canvas-the-detail-is-still-the-work&quot;&gt;AI Is the Canvas. The Detail Is Still the Work.&lt;/h2&gt;

&lt;p&gt;Almost every project I evaluated today used AI in some form — LLMs, RAG pipelines, computer vision models, fine-tuned classifiers. And the starting point worth acknowledging is this: the barrier to building something real has never been lower. A working prototype that would have required a team of engineers and months of effort a decade ago can now be assembled in days. The cost of testing whether a problem is real, whether a solution resonates, whether the hidden need you identified actually exists, has collapsed. A student with a well-understood problem and access to current tools can put something in front of real users faster than most funded startups could five years ago. That changes the calculus of risk significantly — the excuse of not having enough resources to validate an idea is largely gone.&lt;/p&gt;

&lt;p&gt;What impressed me was the fluency with which this generation of students has absorbed these tools. The ambition to apply them to genuinely hard problems — language preservation, accessibility, financial infrastructure, public health — was real and in several cases quite sophisticated.&lt;/p&gt;

&lt;p&gt;The students who will build the most durable things are the ones who go one layer deeper: not just using the model, but understanding what it is actually doing well enough to know where it will hold and where it will not. A RAG pipeline that retrieves accurately from a curated corpus behaves differently on messy real-world data. An agent that navigates known scenarios encounters something different at the edges of its training distribution. The devil, as always, is in that detail — and the detail only reveals itself to someone who has thought carefully about the seams.&lt;/p&gt;

&lt;p&gt;That deeper understanding is also what makes a feedback loop possible in an AI system — and a feedback loop is precisely what turns a capable pipeline into a differentiating product.&lt;/p&gt;

&lt;p&gt;Just as inDrive embedded the market’s response into the transaction itself, an AI system can embed the user’s response into the pipeline — capturing when the output was useful, when it missed the mark, and how the context differed from what the model assumed.&lt;/p&gt;

&lt;p&gt;In both cases, the system is not just producing an answer. It is learning from what actually happens when that answer meets the real world. In a market where the underlying models are increasingly commoditised, that mechanism is where the real differentiation lives.&lt;/p&gt;

&lt;p&gt;What is equally underappreciated is that AI can teach about AI. The process of understanding which approach fits a given problem — whether a fine-tuned model serves better than a RAG pipeline, whether a classification algorithm is more appropriate than a generative one, whether the problem calls for computer vision or structured prediction — is itself a conversation that current tools can facilitate. The students who treat AI as a thinking partner in the design process, not just an implementation tool, will develop intuitions about these choices faster than any curriculum can deliver.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;building-it-is-not-the-same-as-bringing-it-to-the-world&quot;&gt;Building It Is Not the Same as Bringing It to the World&lt;/h2&gt;

&lt;p&gt;There is a generation of engineers ahead of you who built genuinely useful things that nobody ever found. Not because the product was weak. Because the path from a working product to a user who knows about it, chooses it, pays for it, and stays with it — is its own discipline, as demanding as the engineering itself.&lt;/p&gt;

&lt;p&gt;The technical problem and the commercial problem are different problems. Solving one does not solve the other. And the commercial problem — how does this reach the people who need it, at a price that sustains the work, through a channel they actually use — is one that engineering training rarely addresses directly.&lt;/p&gt;

&lt;p&gt;Previous generations of engineers largely had to discover this on their own. That gap in awareness was the norm. It is less excusable now, not because the challenge is smaller but because the knowledge is more accessible. There are more examples, more frameworks, more founders who have documented what they learned. The raw material for understanding commercialisation is available in a way it has never been before.&lt;/p&gt;

&lt;p&gt;What that understanding actually requires, in practice, is thinking through a few questions that the product alone cannot answer.&lt;/p&gt;

&lt;p&gt;Who pays for this — and is that the same person who uses it? In many of the projects built this year, the user and the economic buyer are different. A platform built for students may be paid for by an institution. A tool built for farmers may be funded by an agricultural development programme. Understanding that distinction changes how you price, how you sell, and what features matter most to whom.&lt;/p&gt;

&lt;p&gt;How does someone discover this exists? A product that solves a real problem is still invisible until it reaches the person who needs it. The channel through which a potential user encounters and evaluates your solution is as much a design decision as the interface itself. Cloudways grew largely through word of mouth within communities of developers and small business operators — because the product was good enough that the people using it told others. That was not accidental. It was the result of understanding who the early user was well enough to build something they would naturally recommend.&lt;/p&gt;

&lt;p&gt;What does it cost to serve one user, and does the price reflect that? The projects built this year were almost universally free at the point of use. That is appropriate for a capstone. It is not a sustainable default for a product. Understanding the economics of delivering value — what it costs, what a user would pay, where the margin lives — is the layer of thinking that turns a technically sound product into something that can sustain itself and the people building it. Sometimes the pricing model itself is the insight. inDrive did not just build a negotiation feature — it recognised that in a price-sensitive market, letting users and drivers agree on a fare directly was more trusted than any algorithm. The price became the product’s clearest signal of respect for its users.&lt;/p&gt;

&lt;p&gt;None of this requires a business degree. It requires the same disposition that produced the product in the first place: curiosity about how things actually work, willingness to sit with the uncomfortable questions, and enough respect for the user to understand not just what they need but what they will actually do.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-thing-that-does-not-show-up-in-the-demo&quot;&gt;The Thing That Does Not Show Up in the Demo&lt;/h2&gt;

&lt;p&gt;The projects that stayed with me after today were not always the most technically sophisticated. They were the ones where the student had made the problem genuinely their own.&lt;/p&gt;

&lt;p&gt;That is harder to describe than it is to recognise. It shows in how questions are answered — not whether they are answered, but whether the student reaches for their own understanding or for a prepared response. It shows in the honesty with which limitations are acknowledged. It shows in the specificity of what they would build next, and why.&lt;/p&gt;

&lt;p&gt;That kind of ownership does not come from the project structure. It comes from caring about the problem independently of the deadline — thinking about it outside supervised hours, noticing its dimensions in daily life, having views about what the second version should look like before the first one is finished.&lt;/p&gt;

&lt;p&gt;It is also the quality that matters most when the academic structure falls away and the only reason to keep going is that you believe the problem is worth solving.&lt;/p&gt;

&lt;p&gt;Cursor was built by students who were genuinely frustrated with their own tools. Cloudways was built by someone who believed small businesses deserved infrastructure they could actually use. Careem was built by someone who grew up in Karachi and understood urban mobility in this part of the world at a level that no amount of research could replicate.&lt;/p&gt;

&lt;p&gt;In each case, the problem was personal before it was a company. The passion came first. Acting on it came from trusting that the understanding was real.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-the-next-step-actually-requires&quot;&gt;What the Next Step Actually Requires&lt;/h2&gt;

&lt;p&gt;A project answers one question: can this be built? A product answers a harder one: will someone use this repeatedly, when nobody is asking them to? A company answers the hardest one: can this survive in the real world, when the conditions change and the original assumptions no longer hold?&lt;/p&gt;

&lt;p&gt;Projects prove you can build. Products prove someone cares. Companies prove it survives.&lt;/p&gt;

&lt;p&gt;For anyone who built a final year project this year — at any institution, on any problem — the questions worth sitting with are simpler than they might appear.&lt;/p&gt;

&lt;p&gt;Do you know the specific person your solution is most useful for — precisely enough to describe a day in their life? Do you know what already exists for them, and exactly where it falls short? Do you have a mechanism by which your system will learn from what actually happens when real people use it? And do you understand what it costs to serve one user, who pays for it, and how they will find out it exists?&lt;/p&gt;

&lt;p&gt;These are not business questions layered on top of engineering. They are the next layer of the same problem you have already been working on. The domain knowledge is already there. The year of engagement already happened. The foundation is already built.&lt;/p&gt;

&lt;p&gt;The advantage you have right now is not just insight. It is time — the freedom to explore a problem before the world forces you to move on. That window is real, and it is finite.&lt;/p&gt;

&lt;p&gt;What happens with it next is yours to decide. And that decision is where most projects either end — or begin.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;TECTONICS is a series about how technology organisations actually move — the systems, culture, and scale decisions that determine whether they compound or collapse.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 16 May 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/05/16/FYP-to-market/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/05/16/FYP-to-market/</guid>
      </item>
    
      <item>
        <title>Why Architecture Is Shifting From Diagrams to Guardrails</title>
        <description>&lt;h2 id=&quot;the-cheaper-rewrite-is-not-the-better-rewrite&quot;&gt;The Cheaper Rewrite Is Not the Better Rewrite&lt;/h2&gt;

&lt;p&gt;The previous post in this series argued that AI has lowered the cost of rewrites without lowering the knowledge required to do them well — and that without architectural discipline governing the process, the result is a perpetual rewrite loop: each iteration faster, each iteration less understood than the last &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post does not contradict that argument. It assumes it.&lt;/p&gt;

&lt;p&gt;The previous post described a hard limit: cognitive load ceilings are real, and AI accelerates how quickly teams hit them. The question this post addresses is not how to remove that ceiling — it cannot be removed. It is how to move knowledge out of human cognition and into systems that can preserve, enforce, and evolve it. Specifications. Tests. Architecture as Code. Structured ADRs. These are not workarounds for the cognitive load problem. They are the engineering response to it — externalising what human working memory cannot hold so that AI can be constrained by it rather than unaware of it.&lt;/p&gt;

&lt;p&gt;Three preconditions distinguish a rewrite that produces a genuinely better system from one that restarts the same problems faster. Each precondition raises a deeper question about the role of AI in its own governance — questions the industry is only beginning to ask seriously.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;why-the-same-problems-keep-returning&quot;&gt;Why the Same Problems Keep Returning&lt;/h1&gt;

&lt;p&gt;Joel Spolsky’s 2000 “never rewrite” doctrine was an economic argument, not a technical one &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. Rewrites were expensive not primarily because of engineering hours but because of institutional knowledge — the years of edge cases, discovered constraints, and behavioral understanding embedded in existing systems in ways that were difficult to extract and easy to lose.&lt;/p&gt;

&lt;p&gt;AI has changed the engineering hour cost substantially. It has not changed the institutional knowledge problem. And it has introduced a new pattern that makes that problem harder to manage.&lt;/p&gt;

&lt;p&gt;Call it &lt;strong&gt;architecture by reaction&lt;/strong&gt; &lt;em&gt;(a pattern named here — no established prior term exists for this specific dynamic)&lt;/em&gt;: AI addresses the problem in front of it at each stage of a system’s evolution, without reference to the architectural decisions made in previous stages.&lt;/p&gt;

&lt;p&gt;Consider a typical trajectory:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;v1&lt;/strong&gt; — monolith, perfectly reasonable for MVP scale&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;v2&lt;/strong&gt; — scalability issues hit, AI decomposes into microservices&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;v3&lt;/strong&gt; — latency problems emerge, AI introduces caching and async messaging&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;v4&lt;/strong&gt; — data inconsistency surfaces, AI reintroduces shared state patterns to resolve it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/architecture-to-guardrails/architecture_by_reaction.svg&quot; alt=&quot;architecture by reaction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Each step is locally correct. Globally, the system has regressed — the shared state in v4 recreates the coupling that the microservices decomposition in v2 was designed to eliminate. No single decision was wrong. The sequence, without accumulated memory of why earlier decisions were made, produced the same problem in a different form.&lt;/p&gt;

&lt;p&gt;AI has no memory of v2’s rationale when it generates v4. The institutional knowledge that would say “we moved away from shared state at this boundary precisely because of consistency problems — do not go back” is not in the prompt unless someone put it there. &lt;strong&gt;The same structural mistakes recur not because AI lacks intelligence, but because intelligence without memory is just pattern matching.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This dynamic has a name in the practitioner literature. A widely-discussed critique of agentic coding identifies what it calls the &lt;strong&gt;supervision paradox&lt;/strong&gt;: you need the engineering skills the agent erodes in order to oversee what the agent produces &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;. The more you delegate to AI, the less capable you become of catching what AI gets wrong — and the more you need that capability precisely because AI is generating more that could go wrong. This post does not disagree with that diagnosis. It proposes that the answer is not to delegate less, but to move the supervision from inside the developer’s head into the governance system — where it can operate at scale, persist across team changes, and accumulate rather than erode over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture Decision Records (ADRs)&lt;/strong&gt; are the established mechanism for preserving exactly this institutional memory &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;. An ADR captures not just what architectural decision was made but why — the context, the options considered, the trade-offs accepted, and the consequences anticipated. Fed to AI as context at the start of a rewrite, a library of ADRs is the closest available substitute for the accumulated experience AI lacks. The critical content is not the decision itself but the rejected options and their rationale — “we considered service decomposition at this boundary and rejected it because X” is the institutional memory that prevents the same mistake in the next iteration. Without it, AI has no way of knowing what was tried and failed, and will reproduce the same rejected approaches dressed in newer patterns.&lt;/p&gt;

&lt;p&gt;The three preconditions below are not just preparation for a rewrite. They are the mechanisms by which institutional knowledge is preserved across AI-assisted iterations — making it available to the next rewrite, and the one after that. ADRs are the connective tissue between them.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; AI has lowered the cost of producing code without lowering the cost of understanding it. A rewrite that proceeds without adequate knowledge of the existing system’s domain behavior and failure modes is not cheaper — it is a faster way to accumulate the same debt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/architecture-to-guardrails/governance_chain.svg&quot; alt=&quot;Governance Chain&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;precondition-one-requirements-as-specifications&quot;&gt;Precondition One: Requirements as Specifications&lt;/h1&gt;

&lt;p&gt;Most AI-assisted rewrites fail before a line of code is written. Not because the model is wrong — but because the requirements are.&lt;/p&gt;

&lt;p&gt;The distinction that matters is between requirements as &lt;strong&gt;prose&lt;/strong&gt; and requirements as &lt;strong&gt;specifications&lt;/strong&gt;. Requirements written as prose describe intent in natural language — interpretable, ambiguous, dependent on human judgment for translation into implementation. AI tools reading prose requirements produce implementations consistent with one plausible reading, not necessarily the reading that reflects the domain constraints and behavioral expectations that matter in production. &lt;strong&gt;Prose requirements are instructions. Specification-grade requirements are constraints.&lt;/strong&gt; AI follows instructions probabilistically. Constraints matter because violations can be detected and rejected automatically.&lt;/p&gt;

&lt;p&gt;This principle has been formalised in the industry as &lt;strong&gt;Spec-Driven Development (SDD)&lt;/strong&gt; — a methodology that elevates specifications to executable system truth, making architecture enforceable through continuous validation while AI generation materializes intent into code &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;. SDD’s core distinction, as articulated by Griffin and Carroll, is that traditional specifications are read by humans while SDD specifications execute as validation gates — if code diverges from the spec, the build fails. The industry is converging on this from multiple directions: practitioners building with AI agents have independently arrived at similar conclusions, finding that writing feature specifications in structured formats rather than natural language prompts substantially reduces AI’s tendency to generate plausible but contextually wrong output when given ambiguous instructions &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Requirements written as specifications are structured, verifiable, and precise enough to function as constraints on AI generation rather than guidance for it. They encode not just what the system should do but what it must not do, what invariants must hold, and what the consequences of violating those invariants are &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The objection that immediately arises:&lt;/strong&gt; this exercise was already done when the first version was built. Why repeat it?&lt;/p&gt;

&lt;p&gt;The answer is that it was done, but not in this form. The domain knowledge exists — in the original requirements documents, in production incident records, in the heads of engineers who built and maintained the system. What does not exist is that knowledge translated into a format that AI can consume as a constraint rather than guidance. And crucially, the domain has evolved since the first version. New edge cases have been discovered in production. New business rules have been added. Constraints have emerged from real usage that were not in the original specification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The practical answer is to use AI to accelerate the translation process rather than relying on humans to author everything manually&lt;/strong&gt; &lt;em&gt;(proposed approach — no established prior source covers this specific workflow)&lt;/em&gt;. The process is more tractable than it sounds:&lt;/p&gt;

&lt;p&gt;Feed the existing requirements documents, production incident records, change request history, and any available domain documentation to AI. Ask it to identify gaps, ambiguities, and contradictions. Ask it to generate clarifying questions about what is unclear — specifically around invariants, failure modes, and boundary conditions. Have domain experts answer those questions. Feed the answers back. AI reformats the output as structured, verifiable specifications that can be used to constrain subsequent generation.&lt;/p&gt;

&lt;p&gt;This is not a documentation exercise driven by human effort. It is an AI-assisted extraction and clarification process in which human expertise is the validator rather than the primary generator. The domain experts are answering targeted questions, not authoring documents from scratch. The difference in time and effort is substantial.&lt;/p&gt;

&lt;p&gt;The result is a specification that encodes what the system must do precisely enough that AI can be held to it — and precisely enough that deviations from it can be detected automatically.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; The quality of an AI-assisted rewrite is bounded by the quality of the requirements that govern it. AI can extract, clarify, and reformat existing knowledge into specification-grade constraints — but human validation of those constraints against real domain understanding is not optional.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What a specification-grade requirement looks like in practice&lt;/strong&gt; deserves a concrete example. UML use case specification — with its actor, precondition, main flow, alternate flows, postcondition, and exception flows structure — has been the established standard for capturing behavioral intent precisely since the 1990s &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. The format is well-understood by domain experts and captures branching behavior more naturally than flat invariant statements.&lt;/p&gt;

&lt;p&gt;However, the standard UML use case format was designed for human-to-human communication, not human-to-AI constraint. It lacks three things that make a specification machine-consumable: a falsifiable invariant that AI can translate directly into a test assertion, a violation consequence that encodes the business cost of non-compliance, and linkage to the ADR and fitness function that enforce the decision architecturally.&lt;/p&gt;

&lt;p&gt;The following format is a &lt;strong&gt;proposed concrete implementation of SDD principles&lt;/strong&gt; — combining the established UML use case flow structure with YAML front matter for machine-readable metadata. SDD prescribes that specifications should be executable and authoritative; this format is one way of achieving that at the requirement level. No single established prior source prescribes this specific combination:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SPEC-017&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Payment processing idempotency&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;safety-invariant&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# safety | liveness | business-rule | performance&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;affects&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;payment-service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;bounded-contexts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;payment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;verified-by&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TEST-041&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;linked-adr&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ADR-033&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Actor&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Payment consumer (internal service or external client)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Precondition&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Payment request contains a valid idempotency key&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Payment service is operational&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Main Flow&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;1. Consumer submits payment request with idempotency key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;2. System checks idempotency log for key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;3. Key not found — system processes payment and records outcome against K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;4. System returns payment result&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Alternate Flow: Duplicate Submission&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;1. Consumer submits payment request with idempotency key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;2. System checks idempotency log for key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;3. Key found — system returns stored outcome, no new charge created&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;4. Idempotency log records duplicate attempt as no-op&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Exception Flow: Timeout During Processing&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;1. Consumer submits payment request with idempotency key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;2. System begins processing, timeout occurs before outcome recorded&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;3. Consumer retries with same key K&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;4. System detects in-progress state — waits for completion or rolls back cleanly&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;5. Returns consistent outcome — no duplicate charge under any scenario&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Postcondition&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Exactly one charge exists for any given idempotency key&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Idempotency log contains record of all attempts&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Invariant (machine-verifiable)&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;forall requests r1, r2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;r1.idempotency_key == r2.idempotency_key&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;=&amp;gt; outcome(r1) == outcome(r2) AND charges_created == &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Violation Consequence&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Duplicate charges. Regulatory breach. Chargeback liability.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Out of Scope&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Cross-service idempotency — see SPEC-018&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Three fields in the YAML front matter make this more than a use case document. The &lt;strong&gt;type&lt;/strong&gt; field allows AI to apply different validation strategies to safety invariants versus performance constraints. The &lt;strong&gt;verified-by&lt;/strong&gt; link connects the specification directly to its test, so AI generating a fix for a failing test can immediately identify the specification it must satisfy. The &lt;strong&gt;linked-adr&lt;/strong&gt; closes the loop to the architectural decision that enforces the boundary structurally — giving AI a connected graph of intent rather than an isolated document.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;precondition-two-tests-as-behavioral-contracts&quot;&gt;Precondition Two: Tests as Behavioral Contracts&lt;/h1&gt;

&lt;p&gt;The most expensive tests in an AI-assisted rewrite are not the ones that fail. They are the ones that pass — on code that looks correct but preserves the old system’s structural problems in new form.&lt;/p&gt;

&lt;p&gt;The second precondition follows from the first. If requirements are specifications, tests are their executable form — the mechanism by which specification compliance is verified continuously rather than asserted once at the point of writing. &lt;strong&gt;A test suite that cannot survive an architectural change is not a safety net. It is an anchor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The distinction that matters for a rewrite is between tests written against &lt;strong&gt;implementation&lt;/strong&gt; and tests written against &lt;strong&gt;behavior&lt;/strong&gt;. Tests written against implementation internals — specific classes, methods, internal data structures — are tightly coupled to the architecture of the system they were written for. Carrying them into a rewrite anchors the new implementation to the old architecture, defeating the purpose of the rewrite. Tests written against behavior — describing what the system does from the perspective of the actors that depend on it — travel across a rewrite cleanly and give AI a verifiable target without prescribing internal structure &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The practical implication: unit tests that test internal structure should largely be discarded. Integration and acceptance tests written at behavioral boundaries are the primary inheritance from the old system. Consumer-driven contract tests, which encode the behavioral expectations of each service consumer without prescribing how those expectations are satisfied, are particularly valuable in this context &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;. Property-based tests, which assert that invariants hold across entire categories of inputs rather than specific examples, encode behavioral contracts at a level of generality that constrains AI generation effectively and surfaces edge cases that example-based tests miss &lt;a href=&quot;#ref-11&quot;&gt;[11]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is missing from this picture — and should not be — is the production system itself as a source of test evidence&lt;/strong&gt; &lt;em&gt;(proposed workflow — the Meta paper &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt; covers AI-assisted test generation but the specific practice of using production logs to identify redundant tests alongside missing ones is an extension proposed here)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Production logs, distributed traces, and incident records contain the most accurate description of how a system actually behaves under real conditions. They reveal execution paths that tests do not cover, edge cases that design-time reasoning did not anticipate, and behavioral patterns that exist in production but have no corresponding assertion in the test suite. AI can read this evidence and act on it systematically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Analyse production logs and traces to identify execution paths with no corresponding test coverage — and generate candidate behavioral tests for those paths&lt;/li&gt;
  &lt;li&gt;Identify tests in the existing suite that assert behavior that production logs show never actually occurs — candidates for removal as they test assumptions rather than reality&lt;/li&gt;
  &lt;li&gt;Surface behavioral patterns that appear consistently in production failures and generate property-based tests that encode the invariant being violated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not speculative. AI-assisted test generation tools are already moving in this direction. The key shift is treating the production system as a continuous source of specification evidence — a record of what the system actually does and what it actually fails to do — rather than relying solely on design-time test authorship &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The test suite that emerges from this process is smaller, more behaviorally accurate, and more useful as AI generation guidance than a test suite authored entirely at design time. It also forms the foundation of the feedback loop — each production failure that reveals a missing behavioral contract can be encoded as a new test, and each test added after a failure closes the loop between what the system actually does and what the specification says it should do.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Production logs and traces are the most accurate specification of system behavior available. AI can read them to identify missing behavioral contracts, remove tests that assert fictional behavior, and generate property-based tests that encode the invariants production failures reveal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;precondition-three-architecture-as-code&quot;&gt;Precondition Three: Architecture as Code&lt;/h1&gt;

&lt;p&gt;The first two preconditions constrain what the system does. This one constrains what the system is allowed to become.&lt;/p&gt;

&lt;p&gt;Architecture documentation that lives in a wiki is not architecture governance. It is archaeology — a record of decisions that may or may not reflect what the system currently does, consulted when something breaks and someone needs to understand why.&lt;/p&gt;

&lt;p&gt;The third precondition addresses how architectural intent is preserved and enforced in a world where AI generates code faster than human review can evaluate it. &lt;strong&gt;Documentation describes. Architecture as Code enforces.&lt;/strong&gt; The difference is not cosmetic — it is the difference between a rule someone might read and a constraint the build will not pass without satisfying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture as Code&lt;/strong&gt; is the established term for this approach &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. Rather than documenting architecture as diagrams and prose that drift from reality the moment development begins, Architecture as Code treats architectural decisions as version-controlled, executable artifacts — constraints that can be evaluated programmatically, validated automatically, and enforced continuously in the CI pipeline.&lt;/p&gt;

&lt;p&gt;The tooling landscape for this is mature. Structurizr allows C4 architecture models to be defined in code and kept alongside the codebase they describe &lt;a href=&quot;#ref-14&quot;&gt;[14]&lt;/a&gt;. ArchUnit encodes dependency rules as executable tests — for example, asserting that no class in the domain package imports from the infrastructure package, and failing the build if that rule is violated &lt;a href=&quot;#ref-15&quot;&gt;[15]&lt;/a&gt;. Dependency Cruiser provides equivalent capability for JavaScript and TypeScript ecosystems &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;. Custom linting rules can encode naming conventions, interface contracts, and module boundary constraints. Together these form an architectural specification that is not a document — it is a set of constraints that run on every commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI doesn’t violate architecture. It obeys whatever architecture you forgot to encode.&lt;/strong&gt; This is why encoding matters more than reviewing. A dependency rule that exists only in a team norm will be violated the first time AI generates code under time pressure without that norm in its context. A dependency rule encoded as an ArchUnit test will fail the build regardless of what AI generated, who reviewed it, or how much pressure the team was under.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The question of whether humans are required&lt;/strong&gt; deserves a direct answer. AI can detect violations of encoded rules automatically and reliably. What it cannot yet do reliably is judge whether the rules themselves are correct — whether the boundary drawn between two bounded contexts reflects the actual domain structure or an outdated assumption, whether a dependency rule encodes a meaningful architectural intent or an arbitrary historical constraint. The enforcement of rules once defined can be fully automated. The definition of the right rules still requires human architectural judgment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whether AI can validate that the architecture is consistent with the requirements&lt;/strong&gt; is an open and important question. In principle — if requirements are written as specifications and architecture is encoded as executable constraints — AI can evaluate whether the structural rules are consistent with the behavioral requirements. In practice, the translation between a behavioral specification and an architectural rule is still a judgment that current AI cannot make reliably. This is an active area of development, not a solved problem. For now, that translation requires a human who understands both the domain and the architectural intent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 80-90% similarity risk&lt;/strong&gt; deserves explicit acknowledgment. If AI generates code against the same domain, similar requirements, and a structurally similar architectural specification, there is a genuine risk that it produces something architecturally close to what it would have produced without the preconditions — because the preconditions narrow the solution space toward correct behavior without necessarily producing a different structure. The architectural specification must be written to encode the improvements the rewrite is meant to achieve, not merely to describe the old architecture more precisely. If the old architecture had a coupling problem between two bounded contexts, the new specification must encode a rule that prohibits that coupling — making the old structure architecturally invalid rather than merely undesirable. Without this deliberate encoding of improvements, AI will gravitate toward familiar patterns and the rewrite will produce a structurally similar system dressed in newer code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference architectures address this risk more directly than custom specifications alone.&lt;/strong&gt; A reference architecture is a pre-defined architectural template for a specific class of problem — a known good structural solution encoding proven patterns, boundary definitions, technology choices, and integration approaches for a well-understood domain or system type &lt;a href=&quot;#ref-17&quot;&gt;[17]&lt;/a&gt;. Examples include Microsoft’s Azure Reference Architectures for cloud workloads, the AWS Well-Architected Framework for distributed systems, and domain-specific reference architectures for healthcare data platforms or financial transaction processing. Where a custom architectural specification mostly encodes what is not allowed — prohibiting the structural problems of the old system — a reference architecture encodes what should be present: which service boundaries are appropriate, which communication patterns are proven, which integration approaches have accumulated the most operational evidence.&lt;/p&gt;

&lt;p&gt;Providing a reference architecture as context to AI during generation meaningfully shifts its output distribution away from average training data patterns toward known good structural decisions. This is the practical realisation of your instinct about AI behaving as a junior architect: a junior architect given a reference architecture will apply it faithfully in the common cases it covers, producing better-than-average structural decisions without requiring the depth of experience that would generate those decisions from scratch.&lt;/p&gt;

&lt;p&gt;The nuance — and it is important — is that junior architects given a reference architecture struggle precisely in the cases where it does not quite fit: where the specific domain has requirements the reference architecture’s authors did not anticipate, and where judgment is required about when to follow the template and when to deviate. AI behaves identically. It applies a reference architecture well in the cases it covers and produces structurally questionable output in the edge cases it does not — without signalling that it is doing so. The human architect’s role in this model is specifically to identify where the reference architecture does not fit the domain and to encode those deviations explicitly, rather than relying on AI to exercise correct judgment about them independently.&lt;/p&gt;

&lt;p&gt;Reference architectures also carry known anti-patterns — structural decisions that look reasonable but have failed repeatedly in practice for this class of system. Encoding these as constraints alongside the reference architecture’s positive guidance gives the Architecture as Code specification a head start on the feedback loop: teams can encode known failure modes preemptively from the reference architecture’s accumulated experience, rather than discovering them through production failures and adding fitness functions after the fact.&lt;/p&gt;

&lt;p&gt;The instinct to encode known good domain structure predates AI by decades. Silverston’s &lt;em&gt;Data Model Resource Book&lt;/em&gt; did it at the data layer with pre-built ERDs for core business domains &lt;a href=&quot;#ref-18&quot;&gt;[18]&lt;/a&gt;; Arlow and Neustadt’s &lt;em&gt;Enterprise Patterns and MDA&lt;/em&gt; did it at the domain model layer with reusable UML archetype patterns &lt;a href=&quot;#ref-19&quot;&gt;[19]&lt;/a&gt;. Both embodied the same principle: here is the known good structure for this class of problem, available to accelerate design without requiring every team to rediscover the same solutions. What changes with AI is not the value of that accumulated knowledge but the mechanism of its consumption — from a human reading a reference book to AI consuming structured constraints and applying them directly during generation.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Architecture as Code shifts architectural governance from design-time documentation to continuous automated enforcement. Reference architectures, encoded as executable constraints, shift AI’s output distribution from average patterns toward known good structural decisions — making the similarity risk significantly smaller. But the cases where the reference architecture does not fit the domain still require human judgment to identify and encode explicitly. AI enforces rules. Humans must ensure the rules are the right ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What a fitness function looks like in practice&lt;/strong&gt; deserves a concrete example. Architectural fitness functions are an established concept from Ford, Parsons, and Kua &lt;a href=&quot;#ref-20&quot;&gt;[20]&lt;/a&gt;. The specific format below — with YAML metadata linking each fitness function back to its ADR and specification — is a &lt;strong&gt;proposed extension&lt;/strong&gt; of the established concept, designed to make the governance chain machine-navigable rather than dependent on human knowledge of which rule enforces which decision:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FF-019&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Payment domain must not import from infrastructure layer&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;enforces-adr&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ADR-042&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;enforces-spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SPEC-017&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;tool&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ArchUnit&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# ArchUnit | DependencyCruiser | custom-lint&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;build-fail&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# build-fail | warning | metric&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;threshold&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# zero violations permitted&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Rule (ArchUnit Java example)&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ArchTest&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;public static final ArchRule paymentDomainIsolation =&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;noClasses()&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;.that().resideInAPackage(&quot;..payment.domain..&quot;)&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;.should().dependOnClassesThat()&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;.resideInAPackage(&quot;..infrastructure..&quot;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## What This Catches&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Any class in the payment domain package importing from infrastructure —&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;database clients, HTTP clients, messaging adapters, framework annotations.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## What This Does Not Catch&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Intent drift — whether the boundary itself is still the right one.&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;That requires periodic human architectural review.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Conditions for Relaxing&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;Only with a corresponding ADR update explaining why the boundary&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;is being changed and what replaces the isolation guarantee.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Three fields in the metadata make this format more than an automated test. The &lt;strong&gt;enforces-adr&lt;/strong&gt; and &lt;strong&gt;enforces-spec&lt;/strong&gt; links mean the fitness function is not a free-floating rule — it is the enforcement arm of a documented decision with documented rationale. When it fails, AI can look up why the rule exists before generating a fix, rather than treating the violation as a style preference to be worked around. The &lt;strong&gt;conditions for relaxing&lt;/strong&gt; field is the most important: it prevents AI from simply disabling or weakening the rule when it blocks generation, by requiring a corresponding ADR update that documents why the architectural boundary is being changed.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;keeping-everything-current-as-ai-writes-code&quot;&gt;Keeping Everything Current as AI Writes Code&lt;/h1&gt;

&lt;p&gt;The three preconditions address the starting conditions for a well-governed rewrite. A harder problem is maintaining those conditions as the rewritten system evolves — keeping requirements, tests, and architectural constraints current as AI continues to generate code after the rewrite is complete.&lt;/p&gt;

&lt;p&gt;The drift problem is structural. AI generates decisions faster than humans can document them. Without active intervention, the gap between the specified architecture and the actual architecture widens continuously.&lt;/p&gt;

&lt;p&gt;Three practices mitigate this effectively:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture as a definition of done.&lt;/strong&gt; Every pull request that changes architectural structure — introduces a new dependency, crosses a module boundary, adds an external integration — should require a corresponding update to the architectural specification. Making this a gate on merge rather than a post-hoc obligation is the difference between a living specification and a documentation graveyard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured ADRs as machine-consumable memory.&lt;/strong&gt; Traditional ADRs — lightweight Markdown documents storing title, status, context, decision, and consequences — were designed for human readers &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;. For AI consumption they need to be enriched. The format below is a &lt;strong&gt;proposed extension&lt;/strong&gt; of Nygard’s original ADR format — adding machine-readable fields, structured rejection rationale, fitness function linkage, and explicit conditions for revisiting that no established prior format includes:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ADR-042&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Payment service owns its own data store&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;accepted&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# proposed | accepted | deprecated | superseded&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;2024-03-15&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;supersedes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;superseded-by&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;affects&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;payment-service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;order-service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;service-boundary&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;data-ownership&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;consistency&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;fitness-functions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FF-018&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;FF-019&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Context&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;narrative prose describing the problem&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Options Considered&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Option A&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Shared database&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rejected-because&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;structured rationale&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Option B&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Event-driven sync&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rejected-because&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;structured rationale&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Option C&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Service owns its data — SELECTED&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Decision&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;prose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Consequences&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;prose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;## Conditions for Revisiting&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;explicit statement of what would need to change for this decision&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;to be reconsidered — e.g. &quot;reconsider if team grows beyond 15 engineers&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/architecture-to-guardrails/specification_format_map.svg&quot; alt=&quot;specification format map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Three fields make this format significantly more valuable than prose ADRs for AI consumption. But before explaining them, the framing matters: &lt;strong&gt;the most valuable part of an ADR is not the decision. It is the memory of what failed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The rejected options and their rationale are the institutional memory that prevents AI from reproducing the same approaches in the next rewrite. The &lt;strong&gt;fitness-functions link&lt;/strong&gt; connects rationale to enforcement, so when a fitness function fails AI can look up why the rule exists before generating a fix. The &lt;strong&gt;conditions for revisiting&lt;/strong&gt; field encodes the judgment about when a superseded decision might become relevant again — preventing AI from applying outdated decisions in contexts where circumstances have changed enough to warrant reconsideration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-assisted architecture extraction.&lt;/strong&gt; Tooling can infer the actual architecture of a codebase from its structure — generating dependency graphs, identifying coupling hotspots, surfacing module boundary violations, and comparing the actual architecture against the specified one &lt;a href=&quot;#ref-21&quot;&gt;[21]&lt;/a&gt;. Used in the CI pipeline, this provides continuous validation that the specified and actual architectures remain aligned. Divergences surface as build failures rather than as gradual invisible drift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Periodic architectural review as a structured practice.&lt;/strong&gt; Fitness functions catch rule violations. They do not catch intent drift — the gradual divergence between what the architecture was designed to achieve and what the business now requires of it. This requires human judgment applied periodically: reviewing whether bounded contexts still reflect the domain, whether dependency rules still encode the right constraints, whether the fitness functions are testing the right properties. In an AI-assisted environment this review should happen more frequently, not less — the pace of change is higher and the signals of drift are subtler.&lt;/p&gt;

&lt;p&gt;One failure mode of this governance model deserves naming directly, because it is the most insidious. &lt;strong&gt;Specifications do not prevent drift. They relocate it.&lt;/strong&gt; A stale specification is more dangerous than missing documentation — because it is enforced. When a specification drifts from the domain it was written to represent, the governance system does not weaken. It continues enforcing with the same confidence, against constraints that are no longer correct. The system will fail exactly as specified, even when the specification is wrong. AI generation without constraints produces chaos. Constraints without understanding produce systems that fail more quietly. The periodic architectural review is not optional overhead — it is the mechanism that distinguishes a living governance system from an increasingly authoritative record of outdated decisions.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;the-feedback-loop-from-production-failures-to-architectural-improvement&quot;&gt;The Feedback Loop: From Production Failures to Architectural Improvement&lt;/h1&gt;

&lt;p&gt;Production failures are not incidents to be resolved. They are specifications the system wrote for itself — evidence of behavior the design did not anticipate and the test suite did not encode. &lt;strong&gt;Every failure that produces only a fix and no updated specification is institutional knowledge discarded.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The preceding sections address how to govern a rewrite and maintain that governance over time. They do not fully address the hardest challenge: using the failures that production systems generate as input for architectural improvement rather than local fixes.&lt;/p&gt;

&lt;p&gt;When a production system fails, the failure is a symptom. The architectural cause — a boundary violation, a dependency assumption, a domain concept that has drifted from its implementation — is typically not visible in the failure signal. An alert that fires because payment processing is slow does not say “this is caused by a bounded context boundary eroded in the last rewrite.” A timeout under load does not say “this is caused by coupling between the order domain and inventory domain introduced when AI generated code without reference to the domain model.”&lt;/p&gt;

&lt;p&gt;Translating failure symptoms into architectural causes requires a human who understands both the failure and the system’s architectural intent. This is exactly the category of understanding that architecture by reaction erodes over time. The less institutional knowledge the team has accumulated, the harder it becomes to diagnose failures as architectural problems rather than implementation bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can be structured is the process:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every significant production incident should include an architectural review step — a deliberate question of whether the failure reveals a structural issue the fitness functions did not catch. Failures that reveal architectural issues should produce not just a fix but an updated fitness function — a new automated check that would have caught the structural problem earlier. Requirements that production failures expose as incomplete should be updated as specifications. Tests that production failures reveal as missing should be generated from the failure evidence and added to the suite.&lt;/p&gt;

&lt;p&gt;This is how the feedback loop accumulates rather than degrades — not by automating away the need for architectural judgment, but by encoding the results of that judgment into the specifications, tests, and fitness functions that govern future generation. Each iteration of the loop, if run deliberately, leaves the system better specified than it was before the failure. Each iteration run carelessly — patching the symptom, leaving the cause unaddressed — leaves the system slightly less understood.&lt;/p&gt;

&lt;p&gt;The honest answer to whether this loop can be made reliable is: more reliable, not fully reliable. The boundary of its reliability is the depth of human architectural understanding available to operate it. That understanding is the one resource AI cannot generate on demand — and it is the one resource that architecture by reaction systematically erodes.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; The feedback loop between production failures and architectural improvement accumulates knowledge when failures produce updated specifications, new fitness functions, and additional behavioral tests. It degrades when failures produce only local fixes. The difference is not tooling — it is whether the team has retained enough architectural understanding to diagnose the cause rather than just treating the symptom.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;what-this-means-for-engineering-leaders&quot;&gt;What This Means for Engineering Leaders&lt;/h1&gt;

&lt;p&gt;Three practices distinguish organizations that navigate AI-assisted rewrites well from those that restart the same cycle faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use AI to extract and reformat institutional knowledge, not to replace it.&lt;/strong&gt; The domain knowledge required for specification-grade requirements already exists — in requirements documents, incident records, change histories, and the experience of engineers who built and maintained the system. AI can extract it, surface gaps, ask clarifying questions, and reformat it into machine-consumable specifications. Human domain expertise is the validator of that output, not the primary author of it. The investment is in structuring the extraction process, not in authoring from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat the CI pipeline as the primary architectural governance mechanism.&lt;/strong&gt; Human architectural review cannot operate at the speed AI generates code. Fitness functions, dependency rules, and structural tests in the CI pipeline can. Every architectural rule encoded as an automated check is a unit of governance that operates continuously without consuming human review capacity &lt;a href=&quot;#ref-22&quot;&gt;[22]&lt;/a&gt;. The investment compounds — each rule added after a production failure means that failure cannot recur undetected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build the feedback loop deliberately and protect the judgment required to operate it.&lt;/strong&gt; Production failures are the most valuable source of architectural information available. Capturing that information — as updated specifications, new fitness functions, refined behavioral tests — is the mechanism by which the governance model accumulates knowledge rather than degrading. But the loop requires human architectural judgment to translate symptoms into causes. That judgment erodes when generation outpaces comprehension. Protecting it — through deliberate comprehension investment, through architectural reviews that prioritize understanding over velocity — is the leadership decision that determines whether the loop runs well or runs empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know when a rewrite is justified and when it is not.&lt;/strong&gt; The governance model described in this post is not free. Writing specification-grade requirements, designing behavioral test suites, encoding architectural constraints, and maintaining structured ADRs represents real investment. That investment is justified when the expected system lifespan is long, when regulatory or compliance exposure is high, when the domain is complex and domain knowledge hard to replace, or when the rewrite is intended to produce a materially different architecture rather than cleaner code. It is not justified when the system is genuinely short-lived, when the domain is simple and well-understood, or when the cost of the governance model exceeds the cost of the architectural debt it prevents. The threshold question is not “should we govern our AI-assisted rewrite?” but “does the expected value of this system warrant the investment in governing it properly?” A system expected to run for five years with a team of ten engineers warrants the full model. A prototype expected to be replaced in eighteen months does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Know when an organization is not ready to rewrite yet.&lt;/strong&gt; The preconditions are not just preparation for a rewrite — they are diagnostic criteria for rewrite readiness. An organization that cannot articulate its domain invariants with enough precision to write verifiable specifications is not ready. An organization whose test suite consists entirely of implementation-coupled unit tests is not ready — the behavioral contracts that a rewrite needs as a target do not exist. An organization with no ADRs has no institutional memory to feed to the AI governing the rewrite. In each of these cases, the right investment is not to begin the rewrite but to build the preconditions first. The governance model built during that investment will serve not just the rewrite but every iteration of the system that follows it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/architecture-to-guardrails/rewrite_readiness.svg&quot; alt=&quot;Rewrite readiness diagnostic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Address the test pyramid explicitly before a rewrite begins.&lt;/strong&gt; A rewrite inherits a test suite that was written for a system it is about to discard. Not all of that suite travels. Unit tests that test implementation internals — specific classes, methods, internal state — should be discarded. They are anchors to the old architecture and will constrain the new one. Integration tests written at behavioral boundaries should be kept and reviewed for continued relevance. Acceptance tests and contract tests that encode behavioral expectations at system and service boundaries are the primary inheritance — they are the executable specifications that tell AI what the new system must do without prescribing how it must be built. The rule of thumb: if a test would fail because you changed how something works internally but not what it does externally, discard it. If a test would fail only because the system stopped doing something users or dependents rely on, keep it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redefine what architects do.&lt;/strong&gt; This is the point most leadership conversations about AI and architecture avoid. The governance system described in this post does not reduce the need for architects — it changes what they are for. Before AI, the architect designed systems and enforced discipline through review and team norms. In an AI-assisted organisation with a mature governance system, the architect’s primary responsibility is authoring the governance system itself — what the SDD literature calls &lt;strong&gt;SpecOps&lt;/strong&gt;: treating specification authoring as a first-class engineering surface, with the same quality practices, version control, and continuous improvement applied to production code &lt;a href=&quot;#ref-23&quot;&gt;[23]&lt;/a&gt;. In practice this means writing specifications precise enough to constrain generation, defining the ADR structure that preserves institutional memory, encoding fitness functions that enforce architectural intent, diagnosing production failures as architectural causes rather than implementation bugs, and judging when conditions for revisiting a decision have genuinely been met. This is a more abstract job than designing systems directly — and a more powerful one. A well-designed governance system enforces architectural intent at the speed AI generates code. No architect reviewing pull requests manually ever could.&lt;/p&gt;

&lt;p&gt;The operationalization of this approach is already visible in production tooling. Addy Osmani’s open-source Agent Skills project encodes the workflows and quality gates that senior engineers actually use — spec before code, test before merge, ADRs in the ship checklist — as structured markdown skills that AI agents can consume as persistent context governing every development decision &lt;a href=&quot;#ref-24&quot;&gt;[24]&lt;/a&gt;. This is governance-system authorship made practical: the architect defines the skills, the agent operates within them. The question for engineering leaders is not whether architects are still needed. It is whether the architects on their teams have been given the mandate, the tools, and the time to author governance systems rather than just review code.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;conclusion-the-loop-can-be-made-better-it-cannot-be-made-automatic&quot;&gt;Conclusion: The Loop Can Be Made Better. It Cannot Be Made Automatic.&lt;/h1&gt;

&lt;p&gt;There is one thing this post should say directly that it has so far only implied: &lt;strong&gt;externalising knowledge does not remove the cognitive load ceiling. It moves it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before — the ceiling was in the code. Teams hit it when they could no longer hold the system in their heads. Now — the ceiling is in the governance system. Teams hit it when they can no longer reason confidently about the specifications, fitness functions, ADRs, and feedback loops that govern the code. That is harder — but it fails differently. Cognitive overload in code is invisible until the system breaks in production. Cognitive overload in governance surfaces as failing fitness functions, broken tests, and violated constraints — signals that are detectable, versionable, and correctable before failure propagates. The governance ceiling is not lower. It is more visible. And visibility is what makes it manageable.&lt;/p&gt;

&lt;p&gt;The feedback loop can be made more reliable. It cannot be made automatic. At every point — translating failure symptoms into architectural causes, validating that fitness functions test the right properties, judging when an ADR’s conditions for revisiting have been met — human architectural understanding is required. That understanding is now directed not at the code but at the governance system. The architect’s job is to keep that system honest.&lt;/p&gt;

&lt;p&gt;The question is not whether to build guardrails. It is whether the people building them understand that the guardrails themselves are now the system.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources--further-reading&quot;&gt;Sources &amp;amp; Further Reading&lt;/h2&gt;

&lt;p&gt;[1] &lt;a name=&quot;ref-1&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;&lt;strong&gt;Aathawerani, A. (2026)&lt;/strong&gt; — &lt;em&gt;The Cognitive Load Ceiling: What AI Is Doing to Software Architecture — and Why the Rewrite Is No Longer the Last Resort&lt;/em&gt;&lt;/a&gt;
The preceding post in this series, establishing the cognitive load ceiling framework and its disruption by AI-assisted development.&lt;/p&gt;

&lt;p&gt;[2] &lt;a name=&quot;ref-2&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/&quot;&gt;&lt;strong&gt;Spolsky, J. (2000)&lt;/strong&gt; — &lt;em&gt;Things You Should Never Do, Part I&lt;/em&gt;&lt;/a&gt;
Joel on Software.
The landmark essay establishing the economic — not technical — case against rewrites, grounded in the institutional knowledge cost of discarding working systems.&lt;/p&gt;

&lt;p&gt;[3] &lt;a name=&quot;ref-3&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://larsfaye.com/articles/agentic-coding-is-a-trap&quot;&gt;&lt;strong&gt;Faye, L. (2025)&lt;/strong&gt; — &lt;em&gt;Agentic Coding is a Trap&lt;/em&gt;&lt;/a&gt;
larsfaye.com.
A practitioner critique of agentic coding workflows identifying the supervision paradox — that delegating code generation to AI erodes the engineering skills required to supervise what AI produces, creating a compounding vulnerability as delegation increases.&lt;/p&gt;

&lt;p&gt;[4] &lt;a name=&quot;ref-4&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions&quot;&gt;&lt;strong&gt;Nygard, M. (2011)&lt;/strong&gt; — &lt;em&gt;Documenting Architecture Decisions&lt;/em&gt;&lt;/a&gt;
Cognitect Blog.
The original proposal for Architecture Decision Records as lightweight, version-controlled documents capturing architectural decisions and their rationale — the conceptual foundation for the structured, machine-consumable ADR format described in this post.&lt;/p&gt;

&lt;p&gt;[5] &lt;a name=&quot;ref-5&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.infoq.com/articles/spec-driven-development/&quot;&gt;&lt;strong&gt;Griffin, L. &amp;amp; Carroll, R. (2026)&lt;/strong&gt; — &lt;em&gt;Spec Driven Development: When Architecture Becomes Executable&lt;/em&gt;&lt;/a&gt;
InfoQ.
Introduces Spec-Driven Development as a methodology in which specifications become executable system truth, architecture is enforceable through continuous validation, and human authority shifts upward from implementation to intent.&lt;/p&gt;

&lt;p&gt;[6] &lt;a name=&quot;ref-6&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://acai.sh/blog/specsmaxxing&quot;&gt;&lt;strong&gt;acai.sh (2025)&lt;/strong&gt; — &lt;em&gt;Specsmaxxing&lt;/em&gt;&lt;/a&gt;
acai.sh.
A practitioner account of the benefits of writing feature specifications in structured formats rather than natural language prompts — demonstrating that structured specifications substantially reduce AI’s tendency to generate contextually wrong output. Independent practitioner convergence on the spec-as-constraint principle that SDD formalises.&lt;/p&gt;

&lt;p&gt;[7] &lt;a name=&quot;ref-7&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.microsoftpressstore.com/store/software-requirements-9780735679665&quot;&gt;&lt;strong&gt;Wiegers, K. &amp;amp; Beatty, J. (2013)&lt;/strong&gt; — &lt;em&gt;Software Requirements, 3rd Edition&lt;/em&gt;&lt;/a&gt;
Microsoft Press.
Comprehensive treatment of requirements engineering with specific guidance on writing verifiable, unambiguous specifications that function as constraints rather than guidance.&lt;/p&gt;

&lt;p&gt;[8] &lt;a name=&quot;ref-8&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.pearson.com/en-us/subject-catalog/p/writing-effective-use-cases/P200000009217/9780321605801&quot;&gt;&lt;strong&gt;Cockburn, A. (2000)&lt;/strong&gt; — &lt;em&gt;Writing Effective Use Cases&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
The definitive practical guide to UML use case specification, establishing the actor/precondition/main flow/alternate flow/postcondition/exception flow structure — the established foundation on which the hybrid specification format in this post builds.&lt;/p&gt;

&lt;p&gt;[9] &lt;a name=&quot;ref-9&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/growing-object-oriented-software/9780321574442/&quot;&gt;&lt;strong&gt;Freeman, S. &amp;amp; Pryce, N. (2009)&lt;/strong&gt; — &lt;em&gt;Growing Object-Oriented Software, Guided by Tests&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
Establishes the distinction between tests written against behavior and tests written against implementation, with practical guidance on designing tests that survive architectural change.&lt;/p&gt;

&lt;p&gt;[10] &lt;a name=&quot;ref-10&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://microservices.io/patterns/testing/service-integration-contract-test.html&quot;&gt;&lt;strong&gt;Richardson, C.&lt;/strong&gt; — &lt;em&gt;Consumer-Driven Contract Testing&lt;/em&gt;&lt;/a&gt;
microservices.io.
Describes the consumer-driven contract testing pattern, which encodes behavioral expectations at service boundaries in a form that constrains implementation without prescribing structure.&lt;/p&gt;

&lt;p&gt;[11] &lt;a name=&quot;ref-11&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-3-030-47147-7_4&quot;&gt;&lt;strong&gt;Hughes, J. (2019)&lt;/strong&gt; — &lt;em&gt;How to Specify It: A Guide to Writing Properties of Pure Functions&lt;/em&gt;&lt;/a&gt;
Midlands Graduate School lecture notes.
Practical guide to property-based testing, covering how to identify and express behavioral invariants that hold across entire categories of inputs rather than specific examples.&lt;/p&gt;

&lt;p&gt;[12] &lt;a name=&quot;ref-12&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://arxiv.org/abs/2402.09171&quot;&gt;&lt;strong&gt;Alshahwan, N. et al. (2024)&lt;/strong&gt; — &lt;em&gt;Automated Unit Test Improvement Using Large Language Models at Meta&lt;/em&gt;&lt;/a&gt;
arXiv:2402.09171.
Documents Meta’s production experience using LLMs to improve existing test suites at scale, including identification of missing coverage and generation of additional behavioral tests from production evidence.&lt;/p&gt;

&lt;p&gt;[13] &lt;a name=&quot;ref-13&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://pragprog.com/titles/mkdsa/design-it/&quot;&gt;&lt;strong&gt;Keeling, M. (2017)&lt;/strong&gt; — &lt;em&gt;Design It! From Programmer to Software Architect&lt;/em&gt;&lt;/a&gt;
Pragmatic Bookshelf.
Introduces architecture as a first-class engineering practice with executable, version-controlled artifacts, providing the conceptual foundation for Architecture as Code approaches.&lt;/p&gt;

&lt;p&gt;[14] &lt;a name=&quot;ref-14&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://structurizr.com&quot;&gt;&lt;strong&gt;Brown, S.&lt;/strong&gt; — &lt;em&gt;Structurizr: Architecture as Code&lt;/em&gt;&lt;/a&gt;
structurizr.com.
The leading tool for defining C4 architecture models as code, enabling architecture diagrams to be generated from version-controlled definitions that live alongside the codebase they describe.&lt;/p&gt;

&lt;p&gt;[15] &lt;a name=&quot;ref-15&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.archunit.org/userguide/html/000_Index.html&quot;&gt;&lt;strong&gt;Kůdela, P.&lt;/strong&gt; — &lt;em&gt;ArchUnit User Guide&lt;/em&gt;&lt;/a&gt;
ArchUnit.
Documentation for ArchUnit, which encodes architectural dependency rules as executable tests that run in the standard test suite and fail the build on violation.&lt;/p&gt;

&lt;p&gt;[16] &lt;a name=&quot;ref-16&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://github.com/sverweij/dependency-cruiser&quot;&gt;&lt;strong&gt;Brugts, S.&lt;/strong&gt; — &lt;em&gt;Dependency Cruiser&lt;/em&gt;&lt;/a&gt;
GitHub.
Open source tool for validating and visualising dependencies in JavaScript and TypeScript projects, providing Architecture as Code enforcement equivalent to ArchUnit for JVM ecosystems.&lt;/p&gt;

&lt;p&gt;[17] &lt;a name=&quot;ref-17&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/software-architecture-in/9780132942799/&quot;&gt;&lt;strong&gt;Bass, L., Clements, P. &amp;amp; Kazman, R. (2012)&lt;/strong&gt; — &lt;em&gt;Software Architecture in Practice, 3rd Edition&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
The foundational academic treatment of software architecture patterns and reference architectures, defining reference architectures as pre-defined structural solutions to well-understood classes of problems.&lt;/p&gt;

&lt;p&gt;[18] &lt;a name=&quot;ref-18&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.amazon.com/Data-Model-Resource-Book-Vol/dp/0471380237&quot;&gt;&lt;strong&gt;Silverston, L. (2001)&lt;/strong&gt; — &lt;em&gt;The Data Model Resource Book, Volumes 1 &amp;amp; 2&lt;/em&gt;&lt;/a&gt;
Wiley.
A library of pre-built, reusable ERDs for core business domains and industry-specific models — an early embodiment of the reference architecture instinct at the data layer.&lt;/p&gt;

&lt;p&gt;[19] &lt;a name=&quot;ref-19&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/enterprise-patterns-and/032111230X/&quot;&gt;&lt;strong&gt;Arlow, J. &amp;amp; Neustadt, I. (2004)&lt;/strong&gt; — &lt;em&gt;Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
A catalog of reusable archetype patterns — UML model components for common business entities like Customer, Product, and Order — operating at the domain model layer.&lt;/p&gt;

&lt;p&gt;[20] &lt;a name=&quot;ref-20&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781491986356/&quot;&gt;&lt;strong&gt;Ford, N., Parsons, R. &amp;amp; Kua, P. (2017)&lt;/strong&gt; — &lt;em&gt;Building Evolutionary Architectures: Support Constant Change&lt;/em&gt;&lt;/a&gt;
O’Reilly Media.
Introduces architectural fitness functions as automated mechanisms for continuously validating architectural properties, enabling organizations to detect structural drift before it becomes unmanageable — the established concept on which the proposed fitness function format in this post builds.&lt;/p&gt;

&lt;p&gt;[21] &lt;a name=&quot;ref-21&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://arxiv.org/abs/2203.04374&quot;&gt;&lt;strong&gt;Tornhill, A. &amp;amp; Borg, M. (2022)&lt;/strong&gt; — &lt;em&gt;Code Red: The Business Impact of Code Quality&lt;/em&gt;&lt;/a&gt;
IEEE/ACM International Conference on Technical Debt.
Empirical study demonstrating that automated code health analysis can identify coupling hotspots and structural decay patterns — providing the evidence base for AI-assisted architecture extraction as a continuous governance practice.&lt;/p&gt;

&lt;p&gt;[22] &lt;a name=&quot;ref-22&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/continuous-delivery-reliable/9780321670250/&quot;&gt;&lt;strong&gt;Humble, J. &amp;amp; Farley, D. (2010)&lt;/strong&gt; — &lt;em&gt;Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
The foundational text establishing the CI/CD pipeline as a continuous quality governance mechanism — the conceptual basis for treating the pipeline as the primary enforcement layer for architectural constraints in an AI-assisted development environment.&lt;/p&gt;

&lt;p&gt;[23] &lt;a name=&quot;ref-23&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.infoq.com/articles/enterprise-spec-driven-development/&quot;&gt;&lt;strong&gt;Krishnan, H. (2026)&lt;/strong&gt; — &lt;em&gt;Spec-Driven Development: Adoption at Enterprise Scale&lt;/em&gt;&lt;/a&gt;
InfoQ.
Extends the SDD framework to enterprise adoption, introducing the concept of SpecOps — specification authoring as a first-class engineering surface with the same quality practices and version control applied to production code.&lt;/p&gt;

&lt;p&gt;[24] &lt;a name=&quot;ref-24&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://addyosmani.com/blog/agent-skills/&quot;&gt;&lt;strong&gt;Osmani, A. (2026)&lt;/strong&gt; — &lt;em&gt;Agent Skills&lt;/em&gt;&lt;/a&gt;
addyosmani.com.
An open-source collection of production-grade engineering skills for AI coding agents — spec before code, test before merge, ADRs in the ship checklist — as structured markdown that agents consume as persistent governance context.&lt;/p&gt;
</description>
        <pubDate>Sat, 09 May 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/architecture/scale/2026/05/09/rewrite-preconditions/</guid>
      </item>
    
      <item>
        <title>The Pipeline Is Not the Problem</title>
        <description>&lt;h1 id=&quot;the-pipeline-is-not-the-problem&quot;&gt;The Pipeline Is Not the Problem&lt;/h1&gt;

&lt;h2 id=&quot;how-sdlc-policies-succeed-or-fail--and-why-most-of-them-become-compliance-theater-within-18-months&quot;&gt;How SDLC policies succeed or fail — and why most of them become compliance theater within 18 months&lt;/h2&gt;

&lt;p&gt;Morpheus does not offer Neo a better version of the Matrix. He offers him the truth about it.&lt;/p&gt;

&lt;p&gt;That distinction matters more than it seems. The Matrix was not broken. It was functional, consistent, and convincing. People lived inside it, went to work inside it, built careers inside it. The problem was not that it failed. The problem was that it was not what it appeared to be.&lt;/p&gt;

&lt;p&gt;There is a pattern that repeats itself in software organizations with uncomfortable regularity — and it has the same shape.&lt;/p&gt;

&lt;p&gt;A team — usually a good one, usually after a painful incident or an audit — invests serious effort into designing a real SDLC policy. They think carefully about stages. They define quality gates. They integrate security tooling. They document risk classification. They write it all down, get it approved, and roll it out.&lt;/p&gt;

&lt;p&gt;Eighteen months later, the policy exists. The pipeline runs. The compliance boxes get checked.&lt;/p&gt;

&lt;p&gt;And the engineers have learned exactly which parts to route around, which gates are safe to ignore, and how to make the metrics look healthy without the underlying reality being healthy.&lt;/p&gt;

&lt;p&gt;Most organizations take the blue pill at this point — not out of negligence, but because the system looks like it is working. The dashboards are green. The audits pass. Nobody is asking hard questions, because the surface is clean.&lt;/p&gt;

&lt;p&gt;If you have ever:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Approved a PR you did not fully understand&lt;/li&gt;
  &lt;li&gt;Reclassified a security finding to unblock a release&lt;/li&gt;
  &lt;li&gt;Watched a failing pipeline get bypassed “just this once”&lt;/li&gt;
  &lt;li&gt;Sat in a post-incident review where everyone agreed the process had been followed and nobody could explain why the incident happened anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You already know this system.&lt;/p&gt;

&lt;p&gt;This is not a story about bad engineers. It is a story about a category error — the belief that a well-designed process, once installed, will sustain itself. That the pipeline is the problem, and therefore the pipeline is the solution.&lt;/p&gt;

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

&lt;hr /&gt;

&lt;h2 id=&quot;the-category-error&quot;&gt;The Category Error&lt;/h2&gt;

&lt;p&gt;When organizations design SDLC policy, they are solving for two different problems simultaneously — and most of the time they do not realize it.&lt;/p&gt;

&lt;p&gt;The first problem is &lt;strong&gt;technical&lt;/strong&gt;: what stages should exist, what tools should run at each stage, how severity should be classified, how database changes should be managed, how releases should be governed. This problem is tractable. It has better and worse answers. It responds to careful design.&lt;/p&gt;

&lt;p&gt;The second problem is &lt;strong&gt;social&lt;/strong&gt;: whether the people inside the system will treat the policy as a shared contract or as an obstacle to route around. Whether a failing pipeline will be fixed or bypassed. Whether a reviewer will apply genuine judgment or perform a ritual. Whether a risk classification will be honest or optimistic.&lt;/p&gt;

&lt;p&gt;The technical problem is where organizations spend most of their design energy. The social problem is what determines whether the policy actually works.&lt;/p&gt;

&lt;p&gt;These are not the same problem. A policy that solves the first without addressing the second is not half a solution. It is an expensive way to produce compliance theater.&lt;/p&gt;

&lt;p&gt;The easiest way to understand your system is not to read the policy. It is to observe what happens when following the policy conflicts with shipping on time.&lt;/p&gt;

&lt;p&gt;This is where most systems quietly fail.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-pipelines-fail-to-enforce-culture&quot;&gt;Why Pipelines Fail to Enforce Culture&lt;/h2&gt;

&lt;p&gt;A CI/CD pipeline is not a neutral technical artifact. It is a representation of what an organization believes matters — and, more importantly, of how much the organization trusts the people building the systems it runs.&lt;/p&gt;

&lt;p&gt;When a pipeline is designed primarily as a control mechanism — to catch engineers doing the wrong thing — it produces a specific cultural response. Engineers begin to relate to it adversarially. The pipeline becomes something to satisfy, not something to learn from. When it fails, the question is not “what does this tell us?” but “how do we get this green?” When it slows delivery, the question is not “is this friction worth it?” but “can we skip this?”&lt;/p&gt;

&lt;p&gt;This adversarial posture is not irrational. It is the natural response to a system that treats its users as compliance subjects rather than decision-makers.&lt;/p&gt;

&lt;p&gt;It would be easy to argue that strong pipelines do enforce behavior — after all, you can block deployments, fail builds, and enforce rules mechanically. But what they enforce is compliance, not intent. And compliance without intent is exactly how systems drift into theater.&lt;/p&gt;

&lt;p&gt;The failure mode looks like this in practice:&lt;/p&gt;

&lt;p&gt;A security scan flags a high-severity finding on a feature branch. The developer doesn’t understand the finding, cannot fix it quickly, and has a sprint deadline. The PR sits. A senior engineer reviews it, doesn’t understand the finding either, approves it anyway, and makes a mental note to address it later. The note is never revisited. The finding gets promoted through the pipeline. At release time it is flagged again, reclassified as a known risk, and documented. The documentation goes into a folder that nobody reads.&lt;/p&gt;

&lt;p&gt;The policy worked exactly as written. Every gate fired. Every log entry was made. The finding traveled from development to production with full auditability and zero meaningful intervention.&lt;/p&gt;

&lt;p&gt;This is compliance theater. It is not a failure of the policy’s technical design. It is a failure of the social contract the policy assumed but never built.&lt;/p&gt;

&lt;p&gt;This is the red pill moment most engineering organizations never take. The blue pill is not ignorance — it is the active choice to keep living inside a system that looks like it is working. Morpheus was not describing a broken world. He was describing a comfortable one. The pipelines pass. The dashboards are green. The audit evidence is filed. And somewhere underneath all of it, the system is hollow — quietly, consistently, invisibly hollow — until something breaks in production and nobody can explain why, because the process that was supposed to prevent it had been theater for months.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-policies-assume-without-saying-so&quot;&gt;What Policies Assume Without Saying So&lt;/h2&gt;

&lt;p&gt;Every SDLC policy contains a set of implicit assumptions about the humans who will operate within it. Most of these assumptions are never written down — because to the people writing the policy, they seem obvious.&lt;/p&gt;

&lt;p&gt;They all reduce to one thing: that people will act with integrity under pressure. That reviewers will apply genuine judgment rather than perform a ritual. That developers will write tests that validate behavior rather than satisfy a threshold. That risk will be classified honestly rather than optimistically.&lt;/p&gt;

&lt;p&gt;None of these are guaranteed by policy text. All of them depend on things the policy cannot directly control: shared understanding, psychological safety, genuine ownership, and the organizational signals that tell engineers whether honesty is rewarded or penalized.&lt;/p&gt;

&lt;p&gt;The most dangerous assumption of all is the one about incentives. A policy tells engineers what they are supposed to do. The incentive structure around them tells them what they are actually rewarded for. When those two things diverge — when the policy says “classify risk honestly” and the culture says “be optimistic so we can ship” — the incentive wins. Every time.&lt;/p&gt;

&lt;p&gt;And this is the part no policy document admits.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;forward-only-is-a-culture-decision-dressed-as-a-technical-one&quot;&gt;Forward-Only Is a Culture Decision Dressed as a Technical One&lt;/h2&gt;

&lt;p&gt;Consider a specific design choice that appears in well-designed SDLC policies: the forward-only principle.&lt;/p&gt;

&lt;p&gt;The rule is straightforward. When something breaks, you fix it forward. No reverts. No “we’ll just roll back and figure it out later.” The code goes forward, the database migrations go forward, the releases go forward.&lt;/p&gt;

&lt;p&gt;On the surface this looks like a technical constraint. It is not. It is a cultural stance.&lt;/p&gt;

&lt;p&gt;Forward-only development assumes that the team will invest in making changes safe before they are made, not after. It assumes that regression tests will be written with genuine intent. It assumes that database migrations will be designed to be incrementally safe, not just functionally correct. It assumes that engineers will declare architectural impact honestly before it is reviewed, not retroactively justify it afterward.&lt;/p&gt;

&lt;p&gt;Without those assumptions being socially true, the forward-only rule produces a different outcome: teams that cannot revert accumulate forward-fixes that are poorly understood, stacked on top of each other, each one carrying the technical debt of the emergency it was meant to resolve. The principle that was designed to enforce discipline becomes the mechanism by which undisciplined decisions are permanently baked into the system.&lt;/p&gt;

&lt;p&gt;The same pattern holds for every structurally significant policy decision. Mandatory impact analysis is only as good as the honesty of the engineers declaring it. Severity classification is only as good as the judgment of the engineers applying it. Architectural validation is only as good as the understanding of the engineers reviewing it.&lt;/p&gt;

&lt;p&gt;Policy gives these decisions a structure. Culture gives them a substance. Without both, you have a form without a function.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-social-contract-of-a-quality-gate&quot;&gt;The Social Contract of a Quality Gate&lt;/h2&gt;

&lt;p&gt;A quality gate works when the people on both sides of it share an understanding of what it is for.&lt;/p&gt;

&lt;p&gt;On one side is the developer who has written code, declared its risk, included tests, and submitted a merge request. On the other side is a reviewer who is being asked to validate that the change is what it claims to be — correctly implemented, honestly classified, adequately tested, safe to integrate.&lt;/p&gt;

&lt;p&gt;This is not a mechanical check. It is a judgment call, made by a person who must understand the change well enough to evaluate it fairly. The policy can specify what the reviewer must check. It cannot specify whether the reviewer will develop the understanding necessary to check it meaningfully.&lt;/p&gt;

&lt;p&gt;This has an important implication: the quality gate is only as strong as the shared context between the person who wrote the change and the person reviewing it. When that context is thin — because the reviewer is unfamiliar with the affected domain, because the change is large, because the team is under delivery pressure, because the code was generated by an AI tool that neither person fully understands — the gate fires without doing useful work.&lt;/p&gt;

&lt;p&gt;The ritual is performed. The substance is absent.&lt;/p&gt;

&lt;p&gt;Healthy SDLC cultures invest continuously in the shared context that makes gates meaningful. This means code ownership that is real, not nominal. It means reviewers who are genuinely qualified to review the things they are asked to review. It means teams that are small enough to maintain shared understanding of the systems they own. It means the time to actually do the review, not the expectation that review will happen in the margins around other work.&lt;/p&gt;

&lt;p&gt;These are organizational commitments. They cannot be mandated by a pipeline.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;devsecops-and-the-alert-processing-trap&quot;&gt;DevSecOps and the Alert Processing Trap&lt;/h2&gt;

&lt;p&gt;Security integration in CI/CD suffers from a specific version of this problem that is worth naming directly.&lt;/p&gt;

&lt;p&gt;The technical design of DevSecOps is tractable. Run fast, signal-oriented security checks on feature branches. Run full SAST, SCA, and authenticated DAST at integration. Classify findings by genuine severity. Block only what actually warrants blocking.&lt;/p&gt;

&lt;p&gt;The design philosophy behind this is sound: security controls exist to support decisions at each stage of the pipeline, not to generate artifacts that satisfy an auditor. A CRITICAL finding that blocks a pipeline must be critical enough that a reasonable engineer would agree it should block. A MAJOR finding that is logged but not blocking must be tracked with genuine intent to resolve, not filed and forgotten.&lt;/p&gt;

&lt;p&gt;The failure mode — and it is extremely common — is that organizations implement the technical structure without implementing the decision discipline it requires. The backlog grows. The findings are triaged. The system records activity. The risk accumulates. The security posture degrades continuously while the compliance posture remains technically intact. Every finding is documented. None of them are fixed.&lt;/p&gt;

&lt;p&gt;This is not a tooling problem. The tools are working as designed. It is a culture problem: the organization has optimized for producing security evidence rather than for being secure.&lt;/p&gt;

&lt;p&gt;The distinction matters because they produce different behaviors at every decision point. An organization optimizing for evidence asks “does this finding need to block the pipeline?” and answers that question based on whether blocking it will delay the release. An organization optimizing for security asks “does this finding represent real risk?” and answers based on the actual threat. These are different questions, and they produce different answers, and the difference accumulates over time into a materially different security posture.&lt;/p&gt;

&lt;p&gt;No CI/CD policy can mandate the second question if the culture is asking the first.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-metrics-trap&quot;&gt;The Metrics Trap&lt;/h2&gt;

&lt;p&gt;Organizations that instrument their SDLC policies carefully — tracking pipeline pass rates, mean time to resolution, security finding counts, coverage percentages — will eventually discover that their metrics are healthy and their systems are not.&lt;/p&gt;

&lt;p&gt;This is not a paradox. It is the predictable outcome of measuring outputs rather than intent.&lt;/p&gt;

&lt;p&gt;A pipeline pass rate tells you whether pipelines are passing. It does not tell you whether the tests that pass them are meaningful, whether the findings that don’t block them are being resolved, whether the risk classifications are honest, or whether the architectural gates are being applied with genuine understanding.&lt;/p&gt;

&lt;p&gt;A coverage percentage tells you what fraction of the codebase is touched by tests. It does not tell you whether those tests would catch a real regression, whether the edge cases that matter are covered, or whether the tests were written to validate behavior or to satisfy the metric.&lt;/p&gt;

&lt;p&gt;A mean time to resolution for security findings tells you how quickly findings are closed. It does not tell you whether they were closed by remediation or by reclassification.&lt;/p&gt;

&lt;p&gt;The logs were correct. The decisions were not.&lt;/p&gt;

&lt;p&gt;Metrics are not the problem. The problem is treating metrics as a proxy for the thing the metrics are supposed to measure. When a team understands that it will be evaluated by the metric rather than the underlying reality, optimizing for the metric becomes the rational strategy. The measurement becomes the goal. The goal becomes invisible.&lt;/p&gt;

&lt;p&gt;This is Goodhart’s Law operating in an SDLC context, and it is one of the most reliable failure modes in engineering governance.&lt;/p&gt;

&lt;p&gt;The solution is not to abandon metrics. Removing them doesn’t produce a healthier culture — it produces ambiguity, which usually turns into bias or politics. The solution is to demote metrics from authority to evidence. Use them to understand performance. Use judgment to reward it.&lt;/p&gt;

&lt;p&gt;The earliest sign of policy decay is not failure. It is silent reclassification — when teams start quietly downgrading severity to keep flow moving. By the time it is visible, it has been happening for months.&lt;/p&gt;

&lt;p&gt;The metrics that reveal this are not the ones most organizations track. Track reopened bugs, not tickets closed. Track incidents caused by “known risks” that were documented and not fixed. Track the time between detection and actual remediation, not closure. Track how many times pipelines are bypassed. These expose reality instead of rewarding appearances.&lt;/p&gt;

&lt;p&gt;And recognize that building a system where people genuinely engage with metrics as signals — rather than gaming them as targets — has a cost. It requires slower short-term delivery, more friction in planning, more uncomfortable conversations. If an organization is not willing to pay that cost, it will get compliance theater instead. That is not a failure of tooling or policy design. It is a choice.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-actually-sustains-a-policy&quot;&gt;What Actually Sustains a Policy&lt;/h2&gt;

&lt;p&gt;If pipelines cannot enforce culture, and metrics cannot substitute for judgment, and policy text cannot guarantee honesty — what actually determines whether an SDLC policy works over time?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/pipeline-not-problem/sdlc-two-pillars.svg&quot; alt=&quot;The two pillars of a working SDLC policy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Three things, consistently, in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: the policy must be legible to the people operating within it.&lt;/strong&gt; Not legible in the sense that they can read it, but legible in the sense that they understand why each element exists — what risk it addresses, what failure it prevents, what the organization would look like without it. A developer who understands why forward-only development matters will make different decisions than one who sees it as an arbitrary constraint. A reviewer who understands why impact analysis exists will apply it differently than one who sees it as a checkbox. Legibility requires investment in explanation, not just documentation. It requires the organization to treat policy education as an engineering discipline, not an onboarding formality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: the incentive structure must be aligned with the policy, not merely adjacent to it.&lt;/strong&gt; This means that honest risk classification is rewarded, not penalized. That a developer who raises a genuine concern about a change’s safety is supported, not pressured. That a team that slows down to address a real architectural problem is respected, not seen as blocking delivery. That post-incident reviews result in policy improvements rather than blame allocation. Incentive alignment cannot be mandated. It is expressed through the hundreds of small decisions leaders make about what they visibly value, what they tolerate, and what they hold people accountable for.&lt;/p&gt;

&lt;p&gt;Aligning incentives with policy will slow delivery in the short term. Some releases will be delayed. Some concerns will be uncomfortable to raise and more uncomfortable to act on. If an organization is not willing to accept that cost, the incentives will drift back toward throughput — and the policy will become decoration. This is not a cultural failure. It is a predictable system outcome. Once engineers learn that risk can be reclassified to unblock delivery, that behavior is extremely difficult to reverse. Behavior learned under pressure becomes the system’s default. Policy updates don’t erase it. The system does not reset when you update the policy. It remembers what was rewarded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third: the policy must evolve.&lt;/strong&gt; An SDLC policy written at a point in time reflects the organization’s understanding of its risks and constraints at that moment. Six months later the team is different, the product is different, the threat landscape is different, the tooling has changed. A policy that does not update becomes progressively less accurate as a representation of what the organization actually needs — which means it becomes progressively less legitimate in the eyes of the people operating within it. Policies that stop evolving start to be ignored. The mechanism for updating a policy is not a quarterly review meeting. It is the post-incident review that asks “what in our process failed to prevent or catch this?” and the engineering retrospective that asks “what in our pipeline is generating friction without generating value?” It is the ongoing, institutionalized question of whether the policy is actually working — asked by the people who know, which is the engineers running it.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-policy-as-a-living-system&quot;&gt;The Policy as a Living System&lt;/h2&gt;

&lt;p&gt;A well-designed SDLC policy is not a document. It is a system — and like any system, its behavior depends on the interactions between its components, not just on the properties of the components themselves.&lt;/p&gt;

&lt;p&gt;The components are the technical elements: the stages, the gates, the tools, the severity classifications, the governance structures. These can be designed carefully, and careful design matters. A policy with sensible staging, honest severity enforcement, forward-only discipline, and layered security integration is genuinely better than one without these things.&lt;/p&gt;

&lt;p&gt;But the interactions that determine the system’s actual behavior are social: the trust between developers and reviewers, the honesty with which risk is declared, the seriousness with which findings are addressed, the organizational will to maintain the policy as it ages.&lt;/p&gt;

&lt;p&gt;An organization that gets the technical design right but neglects the social interactions will produce a system that looks functional from the outside and is hollow at the center.&lt;/p&gt;

&lt;p&gt;An organization that understands the social interactions — that invests in legibility, aligns incentives, creates the conditions for honest judgment, and treats the policy as something that must continuously earn its legitimacy — will find that the technical design becomes self-reinforcing. Engineers will propose improvements because they understand what the policy is for. Reviewers will apply genuine judgment because they feel the weight of the responsibility. Metrics will reflect reality because there is no incentive to make them lie.&lt;/p&gt;

&lt;p&gt;The pipeline is not the problem. The pipeline is the expression of an underlying agreement about what quality means, what risk is acceptable, and what it means to take collective ownership of the systems you build.&lt;/p&gt;

&lt;p&gt;That agreement is not written in YAML. It is not enforced by a CI runner. It is built, maintained, and continuously renewed by the people inside it — or it quietly ceases to exist while the pipelines keep passing and the findings keep getting filed and the systems keep degrading.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-this-means-in-practice&quot;&gt;What This Means in Practice&lt;/h2&gt;

&lt;p&gt;The diagnostic test is simple. When your pipeline fails, what happens next?&lt;/p&gt;

&lt;p&gt;Do engineers investigate the root cause — or look for the fastest way to get it green? The answer tells you whether your pipeline is a quality system or a compliance system.&lt;/p&gt;

&lt;p&gt;If you are responsible for engineering outcomes, this leads to a small number of non-negotiable decisions:&lt;/p&gt;

&lt;p&gt;You must decide whether delivery speed or decision integrity is your real priority. Your system will optimize for whichever one you reward under pressure. Both cannot be equally first.&lt;/p&gt;

&lt;p&gt;You must treat pipeline failures as signals, not obstacles. A failing pipeline is the system working. A bypassed pipeline is the system being dismantled, one exception at a time.&lt;/p&gt;

&lt;p&gt;You must accept that some releases will be delayed if you want honest risk classification. If every release must go out on time, risk will be hidden, not managed.&lt;/p&gt;

&lt;p&gt;You must remove metrics that are being gamed — not just add better ones. Keeping a metric because the dashboard looks good is how systems drift into theater and stay there.&lt;/p&gt;

&lt;p&gt;You must invest in shared context, or your quality gates will become rituals. There is no automation substitute for a reviewer who genuinely understands what they are reviewing.&lt;/p&gt;

&lt;p&gt;And you must be visible about what you reward. If engineers are recognized for raising real concerns that delay delivery, others will raise them. If they are pressured or penalized, the concerns will stop — but the risks will not.&lt;/p&gt;

&lt;p&gt;Culture is not built by what you write down. It is built by what you enforce when it hurts.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-final-observation&quot;&gt;A Final Observation&lt;/h2&gt;

&lt;p&gt;The organizations that have the most sophisticated SDLC policies are not always the ones with the healthiest engineering cultures. Sometimes they are the ones with the most elaborate compliance theater — because the sophistication of the policy became a substitute for the harder work of building the conditions under which it could actually function.&lt;/p&gt;

&lt;p&gt;The organizations with the healthiest engineering cultures often have policies that are simpler than you would expect. Not because they have not thought carefully about risk — but because they have thought carefully about what their people can sustain, what their teams can genuinely own, and what their systems can actually enforce. They have calibrated the policy to the culture rather than the culture to the policy.&lt;/p&gt;

&lt;p&gt;That calibration is where the real design work happens.&lt;/p&gt;

&lt;p&gt;Pipelines don’t fail quietly.&lt;/p&gt;

&lt;p&gt;They succeed quietly — while everything underneath them gets worse.&lt;/p&gt;

&lt;p&gt;The question is always: what kind of organization is the pipeline designed to serve?&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;This is part of TECTONICS — a series on how technology organizations actually move. Systems, culture, and scale.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Previous: &lt;a href=&quot;https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling: What AI Is Doing to Software Architecture&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 02 May 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/05/02/pipeline-not-the-problem/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/05/02/pipeline-not-the-problem/</guid>
      </item>
    
      <item>
        <title>The Cognitive Load Ceiling: What AI Is Doing to Software Architecture — and Why the Rewrite Is No Longer the Last Resort</title>
        <description>&lt;h2 id=&quot;the-architecture-that-was-supposed-to-last&quot;&gt;The Architecture That Was Supposed to Last&lt;/h2&gt;

&lt;p&gt;Every generation of software engineers believes it has found the architecture that will not need replacing. Waterfall gave way to layered architectures, which gave way to service-oriented architectures, which gave way to microservices, which are now giving way to modular monoliths. Each transition arrives with genuine conviction that this time, the underlying structure is sound enough to endure. And each time, that conviction eventually erodes — not through technical failure, but through something more fundamental.&lt;/p&gt;

&lt;p&gt;The pattern is consistent: a new architecture solves a real and pressing problem. Teams adopt it with enthusiasm. The system grows. The overhead of understanding, navigating, and extending it increases steadily. At some point the architecture stops serving the team and starts burdening it. A reckoning follows — a rewrite, a decomposition, a consolidation — and the search for the next architecture begins.&lt;/p&gt;

&lt;p&gt;What is rarely examined in these transitions is the root cause. Organizations do not abandon architectures because they were wrong. They abandon them because the team’s &lt;strong&gt;cognitive load ceiling&lt;/strong&gt; was reached. The architecture outgrew the team’s collective ability to hold it in their heads.&lt;/p&gt;

&lt;p&gt;Now a new force has entered this dynamic. Artificial intelligence — in the form of code generation tools, AI-assisted review, autonomous agents, and LLM-based system components — is simultaneously being positioned as the solution to software complexity and quietly introducing a new class of complexity that has no established name. Three questions follow from this that no engineering leader can afford to defer. Does AI actually follow the architectural disciplines the industry spent decades developing? If it does not, do those disciplines still matter? And when AI-assisted codebases eventually become unmaintainable — as they will — is the rewrite still the expensive last resort it once was, or has AI turned it into something more dangerous: a silver bullet that restarts the problem faster than before? An engineering leader might be forgiven for exclaiming “I’m too old for this” — but the more important question is not whether the pace is overwhelming. It is whether the discipline, the judgment, and the accumulated experience that comes with being old enough to know better can be brought to bear on a tool that has none of those things yet.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;what-cognitive-load-actually-means-in-software&quot;&gt;What Cognitive Load Actually Means in Software&lt;/h1&gt;

&lt;p&gt;The concept of cognitive load originates in educational psychology. John Sweller introduced Cognitive Load Theory in 1988 to describe the limits of working memory when processing new information &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;. Sweller identified three distinct types. &lt;strong&gt;Intrinsic load&lt;/strong&gt; is the inherent complexity of the subject matter — the irreducible difficulty of the problem being solved. &lt;strong&gt;Extraneous load&lt;/strong&gt; is complexity introduced by poor structure, unnecessary friction, or avoidable confusion — overhead layered on top of the real problem. &lt;strong&gt;Germane load&lt;/strong&gt; is the productive effort directed toward building lasting mental models — the cognitive work that actually leads to understanding rather than just familiarity.&lt;/p&gt;

&lt;p&gt;These distinctions translate directly into software engineering. Intrinsic load corresponds to the genuine complexity of the domain: business rules, regulatory constraints, edge cases, and interdependencies that exist regardless of how the system is structured. No architectural choice eliminates this. Extraneous load corresponds to accidental complexity: indirection that adds no value, inconsistent naming conventions, unclear ownership, over-abstraction, and architectural ceremony that generates friction without generating insight. Germane load corresponds to the productive effort engineers invest in building accurate mental models of the system — understanding not just what the code does, but why it is structured the way it is, and what the consequences of changing it might be.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cognitive-load-ceiling/cognitive_load_types.svg&quot; alt=&quot;cognitive-load-types&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Matthew Skelton and Manuel Pais formalized this connection in &lt;em&gt;Team Topologies&lt;/em&gt; (2019), arguing that cognitive load should be treated as a &lt;strong&gt;first-class architectural constraint&lt;/strong&gt; &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. Their central claim is deceptively simple: teams have a finite cognitive capacity, and system design must actively manage how that capacity is allocated. When a team’s cognitive load exceeds its ceiling, delivery slows, defects increase, and morale deteriorates — not because the engineers are less capable, but because the system has exceeded what any human team can reliably reason about.&lt;/p&gt;

&lt;p&gt;This reframes the central question of software architecture entirely. The question is not: &lt;em&gt;which architecture is technically superior?&lt;/em&gt; The question is: &lt;em&gt;which architecture best fits within the cognitive constraints of the teams that must build, operate, and extend it, at the scale they currently face?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer has always changed as organizations grow. It is now changing again, in ways more disruptive than any previous shift, because of AI.&lt;/p&gt;

&lt;p&gt;It is worth noting that this framing is not entirely new. Fred Brooks identified the same underlying constraint in 1975, long before cognitive load theory existed as a formal concept. In &lt;em&gt;The Mythical Man-Month&lt;/em&gt;, Brooks argued that conceptual integrity — a unified, coherent vision of what a system is and how it behaves — is the most important consideration in system design &lt;a href=&quot;#ref-2a&quot;&gt;[2a]&lt;/a&gt;. What he was describing, in the vocabulary available to him, was a system that remains within the cognitive reach of the people responsible for it. Sweller formalized the mechanism in 1988. Skelton and Pais operationalized it in 2019. The constraint itself has been present since the first system outgrew the mind of the person who built it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Complexity does not disappear when you change architecture. It redistributes. Every architectural decision is ultimately a decision about where cognitive load lives and who carries it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI does not remove the cognitive load ceiling. It preserves the constraint, but compresses the timeline on which it is reached.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;how-architecture-has-always-responded-to-the-ceiling&quot;&gt;How Architecture Has Always Responded to the Ceiling&lt;/h1&gt;

&lt;p&gt;The history of software architecture is, at its core, a history of successive attempts to manage cognitive load — without ever quite naming it that way. Understanding what these attempts achieved, and where each one ultimately failed, is necessary context for understanding what AI is now changing.&lt;/p&gt;

&lt;h2 id=&quot;the-monolith-and-its-limits&quot;&gt;The Monolith and Its Limits&lt;/h2&gt;

&lt;p&gt;The monolith is the default starting point not because teams lack imagination but because it is cognitively efficient at small scale. A single codebase, a single deployment unit, a shared data model — the entire system is transparent and navigable. Onboarding is fast. Debugging is local. The system fits inside the team’s collective working memory.&lt;/p&gt;

&lt;p&gt;The ceiling arrives as the codebase grows and the team expands. The same transparency that made the monolith cognitively efficient becomes a liability. Changes in one area affect others in non-obvious ways. No individual engineer can hold the full system in working memory. The release cycle slows because the risk surface of any change is too large to reason about confidently. The monolith did not fail technically. It failed cognitively.&lt;/p&gt;

&lt;h2 id=&quot;microservices-and-the-redistribution-problem&quot;&gt;Microservices and the Redistribution Problem&lt;/h2&gt;

&lt;p&gt;Microservices offered a compelling response: decompose the system into independently deployable services, each small enough to be owned and understood by a single team. Sam Newman’s foundational work articulates this promise — small services enable team autonomy, independent deployability, and targeted scaling &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;. DORA research consistently demonstrates that teams with high deployment autonomy achieve better delivery performance and faster recovery from incidents &lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem is that microservices do not reduce cognitive load. They redistribute it. Each team’s local load decreases because their service is small and well-scoped. But system-level cognitive load grows substantially. Distributed tracing, service mesh configuration, API contract management, eventual consistency, and inter-service failure modes introduce complexity that did not exist in the monolith. Martin Fowler’s concept of the “microservices premium” captures this precisely: the overhead is only justified when the organizational benefits outweigh the operational costs, and many teams adopt microservices before reaching the scale where that trade-off is favorable &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The modular monolith re-emerged as a pragmatic recalibration — a single deployable unit with rigorously enforced internal module boundaries that preserves the cognitive benefits of co-location while introducing domain separation. The underlying lesson was not about deployment topology. It was about cognitive ownership: a team must be able to hold its system responsibility in working memory, and the architectural unit should be sized accordingly.&lt;/p&gt;

&lt;h2 id=&quot;clean-architecture-discipline-as-cognitive-relief&quot;&gt;Clean Architecture: Discipline as Cognitive Relief&lt;/h2&gt;

&lt;p&gt;Clean Architecture and its relatives — Hexagonal Architecture, Ports and Adapters — addressed a different cognitive problem: the entanglement of business logic with infrastructure that makes systems resistant to change and difficult to reason about in isolation. Robert C. Martin’s dependency rule placed the domain model at the center, insulating it from frameworks, databases, and external systems &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The cognitive intent was sound. When infrastructure concerns bleed into domain logic, engineers must hold both the business problem and the infrastructure detail in working memory simultaneously — a compounding of intrinsic and extraneous load. Separating them cleanly reduces that burden. The problem is that the architecture introduced its own extraneous load: a proliferation of interfaces, adapters, and mapping layers that required engineers to navigate multiple abstraction levels to trace a single operation. For teams under delivery pressure with unstabilized requirements, the ceremony generated more cognitive overhead than it relieved. The YAGNI principle — You Aren’t Gonna Need It — periodically reasserted itself as a corrective, collapsing architecture back toward the actual complexity of the problem being solved &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The discipline was right. The dose was frequently wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;domain-driven-design-alignment-as-cognitive-strategy&quot;&gt;Domain-Driven Design: Alignment as Cognitive Strategy&lt;/h2&gt;

&lt;p&gt;Domain-Driven Design, introduced by Eric Evans in 2003, targeted the deepest source of extraneous load in large software systems: the divergence between how the domain experts understood the business and how the software represented it &lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. Bounded contexts, ubiquitous language, and aggregate design were tools for alignment — reducing the translation overhead that occurs when engineers must constantly map between technical structures and domain concepts.&lt;/p&gt;

&lt;p&gt;In complex, long-lived domains, DDD delivered on this promise. Vaughn Vernon’s practical work documents organizations where domain-aligned architecture substantially reduced the effort required to implement domain changes &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;. The ceiling arrived through scale: context mapping across dozens of bounded contexts became its own discipline, ubiquitous language drifted as teams changed, and aggregate boundaries became contested as domains evolved. Full DDD adoption was frequently abandoned, but its vocabulary — bounded contexts, the principle that software structure should mirror domain structure — tended to survive and continue shaping better architectural decisions.&lt;/p&gt;

&lt;h2 id=&quot;the-common-thread&quot;&gt;The Common Thread&lt;/h2&gt;

&lt;p&gt;What connects monoliths, microservices, Clean Architecture, and DDD is not the specific patterns they introduced. It is the underlying problem they were all trying to solve. Each was, in essence, an attempt to keep the system within the cognitive reach of the teams building it. Each succeeded in its original context. Each eventually produced its own overhead that pushed cognitive load toward a new ceiling. The ceiling did not disappear. It moved.&lt;/p&gt;

&lt;p&gt;This matters because AI is now being applied to systems built under all of these disciplines — and in many cases, is generating new code without inheriting the discipline at all.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cognitive-load-ceiling/architecture_ceiling_timeline.svg&quot; alt=&quot;architecture_ceiling_timeline&quot; /&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Every major architectural shift in software history was a cognitive load management strategy with a different name. The patterns differed. The underlying problem was always the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;ai-and-architectural-discipline-does-any-of-this-still-apply&quot;&gt;AI and Architectural Discipline: Does Any of This Still Apply?&lt;/h1&gt;

&lt;p&gt;This is the question the industry is not asking clearly enough. The debate about AI in software development has focused heavily on productivity — how much faster code gets written, how many engineers a team can replace or augment. The more consequential question is architectural: &lt;em&gt;does AI follow the disciplines the industry spent decades developing, and if it does not, do those disciplines still matter?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There is a useful frame for this in an unlikely place. In Lethal Weapon, Martin Riggs is extraordinarily effective — fast, capable, gets results in any given scene. He is also completely unpredictable and operates without regard for the procedural rules that exist to protect the system around him. Roger Murtaugh, his partner, keeps the precinct functional, manages the consequences of Riggs’s methods, and carries the institutional knowledge of why the rules exist. His famous line — “I’m too old for this” — is not an admission of weakness. It is the recognition of an experienced engineer watching someone brilliant operate without understanding the cost of what they are breaking. AI in software development is Riggs. The engineering team is Murtaugh. The architecture is the precinct that has to hold together after the scene ends. The problem is not that Riggs is ineffective. The problem is that he does not know he is too old for this — because he has never been old for anything.&lt;/p&gt;

&lt;h2 id=&quot;what-ai-actually-produces&quot;&gt;What AI Actually Produces&lt;/h2&gt;

&lt;p&gt;Large language models used for code generation are trained on the aggregate corpus of publicly available code. That corpus contains Clean Architecture implementations and layered spaghetti with equal frequency. It contains well-bounded DDD contexts and monolithic data models with domain logic scattered across service classes. It contains thoughtful dependency inversion and circular imports. The model has no inherent preference for any of these. It reproduces patterns proportional to their representation in training data, shaped by the context and instructions it receives at generation time.&lt;/p&gt;

&lt;p&gt;In practice, this means that AI-generated code defaults to the most common patterns in its training data — which are not the most disciplined patterns. Without explicit, sustained prompting that encodes architectural intent, AI tools produce code that is &lt;strong&gt;locally coherent but globally undisciplined&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This distinction matters more than it might initially appear. Local coherence means that any individual function, class, or module looks reasonable in isolation — readable, idiomatic, plausibly structured. Global coherence means that the system as a whole maintains consistent dependency direction, enforced boundaries between domains, and long-term evolvability as requirements change. AI optimizes aggressively for the former. Architecture requires the latter.&lt;/p&gt;

&lt;p&gt;A function looks reasonable. A class looks reasonable. The module structure, the dependency graph, the boundary between domain and infrastructure — these are architectural properties that emerge from hundreds of small decisions made consistently over time. They are properties of the system as a whole, not of any individual unit within it. AI tools operating without architectural guardrails do not make those decisions consistently, because consistency across decisions over time is not what they are optimized for.&lt;/p&gt;

&lt;p&gt;Research on LLM code generation quality supports this. Studies examining the architectural properties of AI-generated code find that it tends to violate separation of concerns, accumulate implicit dependencies, and produce structures that are difficult to extend as requirements change — not because the generated code is wrong at the unit level, but because it is optimized for local correctness rather than systemic coherence &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conways-law-in-an-ai-assisted-world&quot;&gt;Conway’s Law in an AI-Assisted World&lt;/h2&gt;

&lt;p&gt;Melvin Conway observed in 1968 that organizations design systems that mirror their communication structures &lt;a href=&quot;#ref-11&quot;&gt;[11]&lt;/a&gt;. This has proven durable across every architectural era: the system you build reflects the team that built it, its boundaries, its shared understandings, and its blind spots. It is why organizational design and system design cannot be treated as independent problems.&lt;/p&gt;

&lt;p&gt;AI introduces a disruption to this dynamic that has not been fully reckoned with. When a significant portion of a codebase is generated by AI tools operating without deep organizational context, the system no longer mirrors the team that is nominally responsible for it. It mirrors the statistical average of the training corpus — plus whatever architectural intent was encoded in prompts and context at generation time. If that intent was thin or inconsistent, the system mirrors nothing coherent at all.&lt;/p&gt;

&lt;p&gt;The implication for engineering leaders is direct: Conway’s Law does not become irrelevant in an AI-assisted organization. It becomes harder to manage, because the “communication structure” that shapes the system now includes the implicit assumptions baked into AI models that the team did not author, cannot fully inspect, and may not be aware of.&lt;/p&gt;

&lt;p&gt;A system that no longer reflects the structure of the team responsible for it becomes harder for that team to reason about — which is precisely another name for increased cognitive load.&lt;/p&gt;

&lt;h2 id=&quot;are-the-disciplines-still-relevant&quot;&gt;Are the Disciplines Still Relevant?&lt;/h2&gt;

&lt;p&gt;The disciplines — Clean Architecture, DDD, the principles underlying microservices decomposition — remain relevant as &lt;strong&gt;intent&lt;/strong&gt;, but AI has fundamentally changed their relevance as &lt;strong&gt;enforcement mechanisms&lt;/strong&gt;. The reasons the disciplines were developed have not disappeared. Domain logic still becomes entangled with infrastructure if boundaries are not enforced. Systems still become unmaintainable if domain concepts are not aligned with code structure. Cognitive load still accumulates when ownership is unclear and dependencies are invisible. The problems these disciplines were designed to solve are permanent features of software at scale.&lt;/p&gt;

&lt;p&gt;What AI changes is their relevance as &lt;strong&gt;enforcement mechanisms&lt;/strong&gt;. Architectural discipline has always depended on consistent human judgment applied across thousands of small decisions over time. Code review, pair programming, architectural decision records, and team norms were the enforcement layer. AI-assisted development, operating at the speed and volume it enables, produces decisions faster than those enforcement mechanisms can process. A team of five engineers using AI assistance can generate the volume of code that previously required twenty engineers — but it still has five engineers’ worth of review capacity, architectural judgment, and institutional knowledge.&lt;/p&gt;

&lt;p&gt;The disciplines do not become obsolete. They become harder to maintain at the pace AI enables — and more important to maintain precisely because of that.&lt;/p&gt;

&lt;p&gt;This means the enforcement model must shift — from code-level judgment applied by engineers in review, to system-level constraints encoded into the platforms, scaffolding, and tooling through which AI generates code in the first place.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; AI follows architectural disciplines only as faithfully as the context it receives encodes them. Without explicit, maintained architectural intent in every generation context, AI defaults to average patterns — and average patterns do not scale.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;the-rewrite-is-no-longer-the-last-resort&quot;&gt;The Rewrite Is No Longer the Last Resort&lt;/h1&gt;

&lt;p&gt;For two decades, the software industry operated under a doctrine best articulated by Joel Spolsky in 2000: &lt;strong&gt;never rewrite your software&lt;/strong&gt; &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;. The argument was compelling and largely correct. Rewrites are expensive. They take longer than estimated. They discard working code alongside broken code. They lose the accumulated institutional knowledge embedded in existing behavior, including the behavior that nobody documented because it was discovered the hard way. The Netscape rewrite became the canonical cautionary tale. Subsequent decades added more.&lt;/p&gt;

&lt;p&gt;The doctrine held because the underlying economics held. A rewrite of a significant system required assembling a team, rebuilding domain understanding from scratch, replicating years of edge case handling, and delivering nothing to users for months or years. The cost was prohibitive enough that organizations tolerated enormous amounts of technical debt rather than face it.&lt;/p&gt;

&lt;p&gt;It is worth pausing on what that cost drove the industry to build. The entire trajectory of architectural thinking described earlier in this article — microservices, Clean Architecture, Domain-Driven Design, modular decomposition — was motivated, in significant part, by the desire to make the catastrophic rewrite unnecessary. If components are small, bounded, and independently deployable, individual pieces can be replaced without touching the whole. If domain logic is insulated from infrastructure, the infrastructure can change without rewriting the domain. If bounded contexts enforce explicit boundaries, one part of the system can evolve without cascading changes into others. Incremental replaceability was the architectural answer to the rewrite problem. The rewrite was not just expensive — it was the failure state that disciplined architecture was specifically designed to prevent.&lt;/p&gt;

&lt;p&gt;AI has now disrupted both sides of this equation simultaneously. It has weakened the architectural disciplines that were designed to keep the rewrite at bay — by generating code faster than those disciplines can be enforced, and by accumulating comprehension debt that erodes the incremental replaceability those disciplines were meant to preserve. And it has lowered the cost of the rewrite itself: a rewrite that once required eighteen months and a dedicated team can now be substantially accelerated, as AI tools can parse existing codebases, identify patterns, generate new implementations, and assist in migrating behavior. The “never rewrite” doctrine, which was always an economic argument rather than a technical one, is no longer as defensible as it was. Both the prevention and the cure have changed at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is genuinely good news for a specific problem.&lt;/strong&gt; Codebases that have accumulated decades of technical debt, that are built on frameworks no longer maintained, or that are architecturally incompatible with current deployment requirements are now more tractable to address. The prohibitive cost that locked organizations into legacy systems has decreased.&lt;/p&gt;

&lt;h2 id=&quot;the-new-trap&quot;&gt;The New Trap&lt;/h2&gt;

&lt;p&gt;But the rewrite’s reduced cost does not change what it actually produces — and this is where the silver bullet framing becomes dangerous.&lt;/p&gt;

&lt;p&gt;A rewrite addresses the &lt;em&gt;existing&lt;/em&gt; comprehension debt in a system. It does not address the &lt;em&gt;organizational conditions&lt;/em&gt; that produced that debt. If those conditions include heavy reliance on AI code generation without architectural discipline, without strong code ownership practices, and without investment in the mental models engineers hold of the systems they operate — then the rewrite restarts the debt clock at zero, with all of the same conditions in place to run it back up, faster than before.&lt;/p&gt;

&lt;p&gt;There is an additional dynamic specific to AI-assisted codebases that makes this worse. When an AI tool generates code that a team does not fully understand, and that codebase later becomes unmaintainable, the rewrite decision is made against a baseline of low comprehension. The team is rewriting a system they never fully understood. The institutional knowledge that a human-authored codebase accumulates over time — the edge cases discovered, the constraints learned, the decisions made and their rationale — is thinner in an AI-assisted codebase where generation outpaced comprehension from the start.&lt;/p&gt;

&lt;p&gt;Empirical research on software rewrite outcomes consistently identifies the same root cause of failure: teams underestimate the implicit knowledge embedded in existing systems, not because that knowledge is hidden but because it was never fully articulated &lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;. AI-assisted codebases are at elevated risk of this failure mode precisely because the generation process does not require articulation of intent, and the review process — under pressure — often does not demand it either.&lt;/p&gt;

&lt;p&gt;Herb Caudill’s analysis of software rewrite case studies identifies the rewrites that succeeded as sharing one property: the team doing the rewrite had deep knowledge of both the domain and the failure modes of the existing system &lt;a href=&quot;#ref-14&quot;&gt;[14]&lt;/a&gt;. AI reduces the cost of the rewrite. It does not substitute for the knowledge required to do it well.&lt;/p&gt;

&lt;h2 id=&quot;can-ai-fix-what-ai-broke&quot;&gt;Can AI Fix What AI Broke?&lt;/h2&gt;

&lt;p&gt;Before reaching for the rewrite, the obvious question is whether AI can remediate the architectural problems it helped create. The answer is partial, and the boundary between what AI can and cannot do here matters enormously for how engineering leaders should plan.&lt;/p&gt;

&lt;p&gt;AI tools are capable of identifying certain categories of architectural problems with genuine utility. Static analysis tools augmented with LLM reasoning can surface dependency violations, coupling hotspots, naming inconsistencies, circular imports, and deviations from documented patterns. When given explicit architectural rules — dependency direction constraints, module boundary definitions, naming conventions — AI-assisted review can enforce those rules at a scale and consistency that human review alone cannot match. Tools that combine static analysis with LLM-based reasoning, such as CodeScene’s code health analysis, demonstrate that automated architectural assessment is not merely theoretical &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What AI cannot reliably do is identify architectural problems that require understanding &lt;em&gt;intent&lt;/em&gt;. The most consequential architectural issues in a degraded codebase are not the ones that violate explicit rules — those are detectable. They are the ones that violate implicit boundaries: coupling that looks acceptable in isolation but undermines a domain boundary that was never formally encoded, abstractions that were designed for a requirement that has since changed, service responsibilities that have drifted from their original purpose in ways that no static rule captures. Detecting these problems requires knowing why the architecture was designed the way it was — the rationale behind the boundaries, the domain model the structure was meant to reflect, the constraints that shaped early decisions.&lt;/p&gt;

&lt;p&gt;That rationale lives in human memory, architectural decision records, and commit history. In AI-assisted codebases where generation outpaced documentation and comprehension, that rationale is often thin or absent. The AI attempting to remediate the architecture is working without access to the intent that would make its fixes meaningful rather than merely locally coherent. It can detect that two modules are tightly coupled. It cannot determine whether that coupling violates a meaningful domain boundary or reflects a legitimate relationship — because that judgment requires understanding the domain, not just the code structure.&lt;/p&gt;

&lt;p&gt;The deeper problem is self-referential. When AI attempts to fix architectural issues in code it or similar tools generated, it brings the same pattern-matching tendencies that produced the issues in the first place. Without explicit, richly encoded architectural context guiding the remediation, AI-assisted fixes tend to resolve local symptoms while leaving systemic causes intact — or introducing new structural problems of a different kind. The result is an architecture that has been tidied but not understood, which is precisely the condition that makes the next degradation faster and harder to detect.&lt;/p&gt;

&lt;p&gt;AI-assisted architectural remediation is a real and valuable tool for well-defined, rule-based violations in codebases with strong architectural documentation. It is not a substitute for the human judgment required to address intent-based architectural decay. When the decay is primarily of the latter kind — which it will increasingly be in codebases built rapidly with AI assistance and insufficient architectural governance — remediation has meaningful limits, and the rewrite conversation becomes unavoidable sooner than it would in a human-authored codebase with comparable symptom severity.&lt;/p&gt;

&lt;h2 id=&quot;the-doctrine-needs-updating-not-discarding&quot;&gt;The Doctrine Needs Updating, Not Discarding&lt;/h2&gt;

&lt;p&gt;Spolsky’s “never rewrite” was a heuristic for an economic environment that no longer exists. The updated doctrine is not “always rewrite with AI” — it is more precise than that:&lt;/p&gt;

&lt;p&gt;A rewrite is now economically viable in more situations than before. It remains cognitively viable only when the team has sufficient understanding of the existing system’s domain behavior and failure modes to avoid replicating its mistakes. AI changes the cost of the rewrite. It does not change the knowledge required to do it well. And in codebases where AI-assisted development has accelerated comprehension debt accumulation, the rewrite may be more affordable and less tractable at the same time — a combination that has not previously been common in software engineering.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; AI has lowered the cost barrier of the rewrite without lowering the knowledge barrier. Treating it as a silver bullet for AI-generated technical debt is precisely the scenario most likely to produce the next generation of legacy systems — built faster, understood less, and facing the same ceiling sooner.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a broader systemic risk here that deserves naming directly: the &lt;strong&gt;perpetual rewrite loop&lt;/strong&gt;. Historically, the high cost of rewrites acted as a forcing function — it compelled organizations to invest in architectural discipline, because the alternative was too expensive to contemplate. As that cost drops, so does the forcing function. If rewrites become cheap enough to reach for routinely, organizations lose the economic incentive to maintain the architectural disciplines that prevent systems from becoming unmaintainable in the first place. The result is a loop: AI accelerates code generation, comprehension debt accumulates faster, the system becomes unmaintainable sooner, a rewrite is initiated, AI accelerates the rewrite, and the cycle restarts — each iteration faster and less understood than the last. The rewrite ceases to be a reset and becomes a treadmill. This is not a hypothetical risk. It is the logical endpoint of treating AI as a substitute for architectural judgment rather than a tool that operates within it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/cognitive-load-ceiling/perpetual-rewrite-loop.svg&quot; alt=&quot;perpetual_rewrite_loop&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Breaking that loop requires treating the rewrite not as a generation problem but as a knowledge problem. Three preconditions distinguish a rewrite that produces a better system from one that restarts the same cycle faster. First, &lt;strong&gt;requirements must be rewritten as specifications&lt;/strong&gt; — not inherited verbatim from the old system, but revisited, clarified, and structured with sufficient precision that AI can be held to them as verifiable constraints rather than loose guidance. Second, &lt;strong&gt;automated tests must encode behavior, not implementation&lt;/strong&gt; — tests written at the right level of abstraction give AI a target that doesn’t anchor it to the old architecture, allowing a genuinely better structure to emerge. Third, &lt;strong&gt;architecture must be documented as machine-interpretable intent&lt;/strong&gt; — not as a description of what was built, but as a specification of what should be built, precise enough to be encoded into the tooling that governs AI generation and validated continuously as the codebase evolves. Each of these preconditions is operationally deep enough to deserve its own treatment. How to write requirements that function as AI specifications, how to validate that AI-generated code conforms to architecture, and how to keep architecture documentation current as AI writes code at pace — these are the practical questions that follow from this article’s argument, and they will be addressed in a subsequent piece.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;what-leadership-looks-like-now&quot;&gt;What Leadership Looks Like Now&lt;/h1&gt;

&lt;p&gt;For engineering leaders, the convergence of cognitive load theory, architectural history, and AI’s dual impact points toward three practices that distinguish organizations that will navigate this period well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat cognitive load as a measurable architectural input, not a cultural side effect.&lt;/strong&gt; Skelton and Pais argue that team cognitive load should be explicitly assessed before assigning system responsibilities — not estimated informally, but evaluated through structured conversations about system comprehension, change confidence, and time spent navigating versus building &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt;. This discipline becomes more important as AI tools make it easier to produce code faster. Velocity is not a proxy for comprehension. A team that ships rapidly with AI assistance but cannot confidently reason about what it has built is not high-performing — it is accumulating comprehension debt that will surface as architectural fragility under pressure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encode architectural intent explicitly and maintain it continuously.&lt;/strong&gt; AI tools follow architectural discipline only as faithfully as the context they receive encodes it. This means that architectural decisions — dependency rules, boundary definitions, domain language, ownership contracts — cannot remain implicit in team norms and individual judgment. They must be encoded in the tools and contexts that shape AI generation: system prompts, linting rules, architectural fitness functions, and code review criteria that specifically evaluate architectural coherence rather than just functional correctness. Ford, Parsons, and Kua’s concept of architectural fitness functions — automated checks that validate architectural properties over time — becomes significantly more valuable in an environment where generation volume can outpace human review &lt;a href=&quot;#ref-15&quot;&gt;[15]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluate rewrites on knowledge, not cost.&lt;/strong&gt; The economic case for rewrites has strengthened. The knowledge case has not changed. Before committing to an AI-assisted rewrite, engineering leaders should be able to answer: does the team understand the existing system’s domain behavior well enough to replicate it intentionally? Does it understand the failure modes well enough to avoid them? If the answer to either question is no, the rewrite is not yet viable regardless of its cost — and the prerequisite investment is in comprehension, not generation.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;conclusion-the-ceiling-didnt-disappear-it-moved&quot;&gt;Conclusion: The Ceiling Didn’t Disappear. It Moved.&lt;/h1&gt;

&lt;p&gt;Software architecture has never been primarily a technical discipline. It has always been a human capacity discipline — an ongoing negotiation between the complexity of the systems we need to build and the cognitive limits of the people who build them. Every significant architectural shift in the industry’s history has been, at its core, an attempt to keep that negotiation from becoming a rout.&lt;/p&gt;

&lt;p&gt;AI has changed the terms of that negotiation in ways that are genuinely new. It has expanded what small teams can build and accelerated what large teams can ship. It has introduced tools that reduce extraneous cognitive load on routine development work in ways that are measurably real. These are meaningful gains, and dismissing them in favor of a purely cautionary narrative would be intellectually dishonest.&lt;/p&gt;

&lt;p&gt;But AI has also introduced comprehension debt at a scale and speed that existing architectural governance is not equipped to detect. It has disrupted Conway’s Law in ways that make organizational and system alignment harder to maintain. It has made the disciplines that manage cognitive load harder to enforce at the pace it enables. And it has lowered the cost barrier on rewrites without lowering the knowledge barrier — creating the conditions for a new generation of legacy systems built faster, understood less, and hitting their cognitive ceiling sooner than any that came before.&lt;/p&gt;

&lt;p&gt;The organizations that navigate this well will not be those that adopt AI most aggressively or resist it most cautiously. They will be those that understand what AI actually does to the cognitive load ceiling — where it genuinely lifts it, where it quietly raises it in disguise, and where it has rendered old assumptions about cost and discipline obsolete without rendering the underlying problems obsolete along with them.&lt;/p&gt;

&lt;p&gt;What makes a partnership survive difficult terrain is rarely that both partners make the right calls. The reckless partner is not simply reckless — beneath the chaos is a genuine desire to get the job done, to solve the problem in front of them, to protect what matters. That does not make the recklessness harmless. It makes it harder to argue against, because the intent is real. And the responsible partner, over time, is not simply responsible — exposed long enough to the velocity and the results, they begin to absorb the habits of the reckless one. Not out of negligence but out of pressure, out of the intoxicating evidence that it seems to be working, out of not wanting to be the person who slows everything down. Both partners drift. Both make decisions they later regret. What holds them together is not a clean record of good judgment. It is the commitment to carry the consequences side by side.&lt;/p&gt;

&lt;p&gt;There is a question that the responsible partner eventually asks — quietly, without accusation, but with the full weight of someone who has been covering for everyone else for a long time: when is anyone going to cover me? It is the question engineering teams are beginning to ask about AI adoption. They have covered for code they did not fully author. They have covered for architectural drift they did not fully cause. They have covered during incidents at 2am when systems built faster than they were understood finally broke in ways nobody anticipated. They have absorbed the cognitive load, the comprehension debt, and the consequences — while the velocity was celebrated and the shortcuts were encouraged. The question of who covers the team is not a complaint. It is the most important organizational accountability question in AI-assisted software development, and most leadership conversations about AI have not yet seriously asked it.&lt;/p&gt;

&lt;p&gt;The relationship between engineering teams and AI is arriving at that kind of moment. The decisions that led here were made under real pressure by people doing their best with what they had. Some of those decisions will turn out to be wrong. The comprehension debt will surface. The architectural drift will become visible. The rewrites will come. What determines whether organizations survive those moments is not whether they placed the perfect bet on AI early. It is whether they have built the discipline, the shared understanding, and the genuine accountability — in both directions — to face the consequences of imperfect decisions together. To cover each other. To keep moving.&lt;/p&gt;

&lt;p&gt;The ceiling has not disappeared. It has moved. And in some places, it has become harder to see.&lt;/p&gt;

&lt;p&gt;That is precisely when it matters most to look for it — together.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources--further-reading&quot;&gt;Sources &amp;amp; Further Reading&lt;/h2&gt;

&lt;p&gt;[1] &lt;a name=&quot;ref-1&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://doi.org/10.1207/s15516709cog1202_4&quot;&gt;&lt;strong&gt;Sweller, J. (1988)&lt;/strong&gt; — &lt;em&gt;Cognitive Load During Problem Solving: Effects on Learning&lt;/em&gt;&lt;/a&gt;
Cognitive Science, 12(2), 257–285.
The foundational paper introducing Cognitive Load Theory and distinguishing intrinsic, extraneous, and germane load as distinct components of working memory burden.&lt;/p&gt;

&lt;p&gt;[2] &lt;a name=&quot;ref-2&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://teamtopologies.com/book&quot;&gt;&lt;strong&gt;Skelton, M. &amp;amp; Pais, M. (2019)&lt;/strong&gt; — &lt;em&gt;Team Topologies: Organizing Business and Technology Teams for Fast Flow&lt;/em&gt;&lt;/a&gt;
IT Revolution Press.
Establishes cognitive load as a first-class constraint in team and system design, with practical frameworks for assessing and managing cognitive load across engineering organizations.&lt;/p&gt;

&lt;p&gt;[2a] &lt;a name=&quot;ref-2a&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/mythical-man-month-the/0201835959/&quot;&gt;&lt;strong&gt;Brooks, F.P. (1975)&lt;/strong&gt; — &lt;em&gt;The Mythical Man-Month: Essays on Software Engineering&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
The foundational work arguing that conceptual integrity — a unified, coherent vision of the system — is the most important consideration in system design. An early articulation of what cognitive load theory would later formalize: that systems must remain within the cognitive reach of the people responsible for them.&lt;/p&gt;

&lt;p&gt;[3] &lt;a name=&quot;ref-3&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://samnewman.io/books/building_microservices/&quot;&gt;&lt;strong&gt;Newman, S. (2015)&lt;/strong&gt; — &lt;em&gt;Building Microservices: Designing Fine-Grained Systems&lt;/em&gt;&lt;/a&gt;
O’Reilly Media.
The definitive practitioner guide to microservices architecture, covering service decomposition, inter-service communication, and the organizational conditions under which microservices deliver value.&lt;/p&gt;

&lt;p&gt;[4] &lt;a name=&quot;ref-4&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://cloud.google.com/devops/state-of-devops&quot;&gt;&lt;strong&gt;Google Cloud / DORA&lt;/strong&gt; — &lt;em&gt;State of DevOps Reports&lt;/em&gt;&lt;/a&gt;
Annual large-scale industry research on software delivery performance, consistently demonstrating the relationship between team autonomy, deployment frequency, and organizational outcomes.&lt;/p&gt;

&lt;p&gt;[5] &lt;a name=&quot;ref-5&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://martinfowler.com/bliki/MicroservicePremium.html&quot;&gt;&lt;strong&gt;Fowler, M.&lt;/strong&gt; — &lt;em&gt;Microservices Premium&lt;/em&gt;&lt;/a&gt;
martinfowler.com.
Articulates the overhead cost of microservices architecture and the threshold at which that overhead becomes justified by organizational benefits.&lt;/p&gt;

&lt;p&gt;[6] &lt;a name=&quot;ref-6&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/&quot;&gt;&lt;strong&gt;Martin, R.C. (2017)&lt;/strong&gt; — &lt;em&gt;Clean Architecture: A Craftsman’s Guide to Software Structure and Design&lt;/em&gt;&lt;/a&gt;
Prentice Hall.
Presents the dependency rule and clean architecture principles, drawing on Cockburn’s earlier work on hexagonal architecture and ports-and-adapters.&lt;/p&gt;

&lt;p&gt;[7] &lt;a name=&quot;ref-7&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://martinfowler.com/bliki/Yagni.html&quot;&gt;&lt;strong&gt;Beck, K. &amp;amp; Fowler, M.&lt;/strong&gt; — &lt;em&gt;YAGNI (You Aren’t Gonna Need It)&lt;/em&gt;&lt;/a&gt;
martinfowler.com.
Articulates the Extreme Programming principle against speculative generality, arguing that structure introduced ahead of demonstrated need consistently produces higher costs than deferring it.&lt;/p&gt;

&lt;p&gt;[8] &lt;a name=&quot;ref-8&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/domain-driven-design-tackling/0321125215/&quot;&gt;&lt;strong&gt;Evans, E. (2003)&lt;/strong&gt; — &lt;em&gt;Domain-Driven Design: Tackling Complexity in the Heart of Software&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
The foundational text introducing bounded contexts, ubiquitous language, and the aggregate pattern as tools for aligning software structure with domain complexity.&lt;/p&gt;

&lt;p&gt;[9] &lt;a name=&quot;ref-9&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/implementing-domain-driven-design/9780133039900/&quot;&gt;&lt;strong&gt;Vernon, V. (2013)&lt;/strong&gt; — &lt;em&gt;Implementing Domain-Driven Design&lt;/em&gt;&lt;/a&gt;
Addison-Wesley.
Practical guidance on applying DDD in real-world systems, with case studies demonstrating both the benefits of full adoption and the organizational investment it requires.&lt;/p&gt;

&lt;p&gt;[10] &lt;a name=&quot;ref-10&quot;&gt;&lt;/a&gt;Yetiştiren, B., Özsoy, I., Ayerdem, M. &amp;amp; Tüzün, E. (2023) — Evaluating the Code Quality of AI-Assisted Code Generation Tools: An Empirical Study on GitHub Copilot, Amazon CodeWhisperer, and ChatGPT
arXiv:2304.10778.
Empirical study evaluating the code quality of major AI generation tools across validity, correctness, security, reliability, and maintainability metrics — finding consistent code smell accumulation and technical debt in AI-generated code, with maintainability issues present across all tools studied.&lt;/p&gt;

&lt;p&gt;[11] &lt;a name=&quot;ref-11&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://www.melconway.com/Home/Committees_Paper.html&quot;&gt;&lt;strong&gt;Conway, M.E. (1968)&lt;/strong&gt; — &lt;em&gt;How Do Committees Invent?&lt;/em&gt;&lt;/a&gt;
Datamation, 14(4), 28–31.
The original statement of Conway’s Law, observing that organizations design systems that mirror their communication structures — a dynamic that AI-assisted development disrupts in ways not previously encountered.&lt;/p&gt;

&lt;p&gt;[12] &lt;a name=&quot;ref-12&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/&quot;&gt;&lt;strong&gt;Spolsky, J. (2000)&lt;/strong&gt; — &lt;em&gt;Things You Should Never Do, Part I&lt;/em&gt;&lt;/a&gt;
Joel on Software.
The landmark essay establishing the “never rewrite” doctrine, grounded in the economic and knowledge costs of discarding working systems — costs that AI has partially but not wholly changed.&lt;/p&gt;

&lt;p&gt;[13] &lt;a name=&quot;ref-13&quot;&gt;&lt;/a&gt;Erlikh, L. (2000) — Leveraging Legacy System Dollars for E-Business
IT Professional, 2(3), 17–23. IEEE Computer Society.
Documents the consistent underestimation of implicit knowledge embedded in legacy systems, a failure mode elevated in AI-assisted codebases where generation outpaces comprehension.&lt;/p&gt;

&lt;p&gt;[14] &lt;a name=&quot;ref-14&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://medium.com/@herbcaudill/lessons-from-6-software-rewrite-stories-635e4c8f7c22&quot;&gt;&lt;strong&gt;Caudill, H. (2019)&lt;/strong&gt; — &lt;em&gt;Lessons from 6 Software Rewrite Stories&lt;/em&gt;&lt;/a&gt;
Medium.
Comparative analysis of software rewrite outcomes identifying deep domain and failure-mode knowledge as the distinguishing property of successful rewrites.&lt;/p&gt;

&lt;p&gt;[15] &lt;a name=&quot;ref-15&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/building-evolutionary-architectures/9781491986356/&quot;&gt;&lt;strong&gt;Ford, N., Parsons, R. &amp;amp; Kua, P. (2017)&lt;/strong&gt; — &lt;em&gt;Building Evolutionary Architectures: Support Constant Change&lt;/em&gt;&lt;/a&gt;
O’Reilly Media.
Introduces architectural fitness functions as automated mechanisms for continuously validating architectural properties, a practice of increased importance when AI generation volume can outpace human architectural review.&lt;/p&gt;

&lt;p&gt;[16] &lt;a name=&quot;ref-16&quot;&gt;&lt;/a&gt;Tornhill, A. &amp;amp; Borg, M. (2022) — Code Red: The Business Impact of Code Quality — A Quantitative Study of 39 Proprietary Production Codebases
IEEE/ACM International Conference on Technical Debt (TechDebt), pp. 11–20.
Peer-reviewed empirical study across 39 production codebases demonstrating that low-quality code contains 15 times more defects and takes on average 124% longer to resolve issues — establishing automated code health assessment as a measurable, business-relevant signal for architectural decay.&lt;/p&gt;
</description>
        <pubDate>Mon, 23 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/scale/2026/03/23/cognitive-load-ceiling/</guid>
      </item>
    
      <item>
        <title>Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law</title>
        <description>&lt;h2 id=&quot;where-organizational-structure-meets-delivery-economics&quot;&gt;Where Organizational Structure Meets Delivery Economics&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Organizations design systems that mirror their own communication structure.”&lt;br /&gt;
— Melvin Conway, 1967&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Conway wrote that sentence nearly sixty years ago, and engineering teams are still learning it the hard way. Not in architecture reviews. Not in retrospectives. In production, at 2am, when a revert cascades into three new incidents, or when a customer upgrade fails because two teams integrated the same shared schema in incompatible ways and nobody noticed until it was far too late.&lt;/p&gt;

&lt;p&gt;Conway’s Law is not a philosophical observation you cite in a tech talk and then ignore. It is a diagnostic instrument. It will tell you, with brutal accuracy, exactly where your organization is lying to itself.&lt;/p&gt;

&lt;p&gt;In a &lt;a href=&quot;https://aathawerani.github.io/systems/culture/scale/2026/01/02/practical-git-branching-fintech/#/&quot;&gt;previous post on Practical Git Branching for FinTech&lt;/a&gt;, I laid out a concrete branching model for multi-customer financial systems — how release branches protect delivery stability, how customer isolation preserves contractual commitments, and how the structure of your Git workflow must reflect the realities of on-prem deployments, schema evolution, and regulatory versioning.&lt;/p&gt;

&lt;p&gt;That post answered the question: &lt;em&gt;what does a sound delivery structure look like?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post asks the question that should come before it: &lt;em&gt;why does your delivery structure need to look like that — and does your current structure honestly reflect your organizational reality?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer runs through Conway’s Law. Not as philosophy. As a diagnostic.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-question-nobody-asks-before-its-too-late&quot;&gt;The Question Nobody Asks Before It’s Too Late&lt;/h2&gt;

&lt;p&gt;When an engineering team starts struggling — with integration conflicts, unstable releases, endless hotfixes, or customer-specific regressions — the instinct is to reach for process. Add a staging branch. Create a feature freeze window. Gate things more tightly.&lt;/p&gt;

&lt;p&gt;Sometimes those interventions help. Often, they obscure the real problem long enough that it metastasizes.&lt;/p&gt;

&lt;p&gt;The question that actually matters is not “which Git branching model should we use?” It is: &lt;strong&gt;where does complexity actually live in our organization — and is our delivery structure honest about that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In multi-customer FinTech systems specifically, there are two completely different kinds of complexity that constantly get conflated, and conflating them is the root cause of most branching dysfunction in the wild.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development coordination complexity&lt;/strong&gt; asks: how many teams integrate simultaneously? How large are the parallel workstreams? How tightly coupled are the modules? How mature are the internal API contracts? How often do teams step on each other?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delivery and release complexity&lt;/strong&gt; asks: how many customers are on different versions? What are the contractual version commitments? How divergent are customer-specific configurations? How constrained are database upgrade paths? What does the regulatory audit trail require?&lt;/p&gt;

&lt;p&gt;These two forces are not just different in degree. They are orthogonal in nature. You cannot solve delivery complexity by adding more development branches, and you cannot solve coordination complexity by tightening your release governance. Teams that don’t make this distinction clearly will end up building a branching strategy that attacks the wrong problem — and they will feel busy and rigorous while doing it.&lt;/p&gt;

&lt;p&gt;If you misidentify where your real complexity resides, your branching model will fight your architecture instead of supporting it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/designing-for-scale/two_complexities_matrix.svg&quot; alt=&quot;Development-Delivery matrix&quot; /&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;what-conways-law-actually-tells-you-about-your-branches&quot;&gt;What Conway’s Law Actually Tells You About Your Branches&lt;/h2&gt;

&lt;p&gt;Here is how to use Conway’s Law as a diagnostic: look at your Git graph and ask yourself whether its complexity maps to a real communication complexity in your organization.&lt;/p&gt;

&lt;p&gt;If you have one cohesive product team with clear ownership, regular communication, shared context, and strong CI/CD pipelines — and your branch diagram looks like a subway map — that is a red flag. Not because complex branching is always wrong, but because structural complexity you cannot justify with organizational reality is debt in disguise. It is ceremony that provides the feeling of rigor without delivering it.&lt;/p&gt;

&lt;p&gt;In that scenario, your multiple staging branches and integration gates are not protecting you. They are hiding the fact that your team hasn’t truly resolved what “done” means, or what “the product” is at any given moment. The branches are a coping mechanism for a clarity problem.&lt;/p&gt;

&lt;p&gt;Conversely, if you have a genuine multi-team coordination problem — multiple squads working in parallel on shared infrastructure, tight release windows, significant domain overlap — and your trunk is a single unguarded main branch with no integration discipline, that is also a structural lie. You are pretending coordination complexity doesn’t exist, and eventually a merge conflict at 4pm on a Friday before a major customer release will make the lie undeniable.&lt;/p&gt;

&lt;p&gt;The point is not “use trunk-based development” or “don’t use trunk-based development.” The point is that your branching strategy should be an honest representation of your organizational structure. No more complex than it needs to be. No simpler than reality demands.&lt;/p&gt;

&lt;p&gt;Take your current branch model and draw it out. Then draw your organization’s communication structure — who talks to whom, how frequently, about what. If the two diagrams don’t roughly correspond in complexity and topology, your branching model is lying about something. The question is what.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;when-development-is-not-the-hard-part&quot;&gt;When Development Is Not the Hard Part&lt;/h2&gt;

&lt;p&gt;Consider a product maintained by a single cohesive team with shared ownership, continuous integration discipline, and clear domain boundaries. This environment does not suffer from high coordination entropy. There are no parallel squads colliding daily, no large-scale merge storms, no need for multi-team synchronization layers.&lt;/p&gt;

&lt;p&gt;In this setting, adding integration buffers does not reduce risk. It diffuses responsibility. It creates a second “almost-main” baseline that introduces ambiguity about what the product actually is at any given moment.&lt;/p&gt;

&lt;p&gt;Trunk-based development is structurally aligned with this reality:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Short-lived feature branches&lt;/li&gt;
  &lt;li&gt;Immediate integration into a single authoritative baseline&lt;/li&gt;
  &lt;li&gt;Fast conflict discovery&lt;/li&gt;
  &lt;li&gt;Clear source of truth at all times&lt;/li&gt;
  &lt;li&gt;Reduced cognitive overhead for everyone on the team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simplicity, when it matches organizational reality, is not a shortcut. It is a force multiplier.&lt;/p&gt;

&lt;p&gt;The key word is &lt;em&gt;matches&lt;/em&gt;. Trunk discipline is not appropriate because it is fashionable. It is appropriate when development coordination complexity is genuinely low — and in a single-team product, it almost always is.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-trunk-based-development-makes-sense-for-single-team-fintech-products&quot;&gt;Why Trunk-Based Development Makes Sense for Single-Team FinTech Products&lt;/h2&gt;

&lt;p&gt;Let’s be concrete about why this matters specifically in financial systems.&lt;/p&gt;

&lt;p&gt;In financial-grade systems, the most dangerous surface is not your code — it is your persisted state. Database schemas. Transaction records. Authorization policies. Downstream integration contracts. These things do not roll back cleanly. A schema migration that runs in one environment and fails in another is not just a bug. It is a potential data integrity incident. In regulated systems, it can be a compliance event.&lt;/p&gt;

&lt;p&gt;When you integrate continuously into a single trunk, migration conflicts surface immediately. Contract violations between services are detected within minutes of the offending commit. Security scanning evaluates the actual integrated system, not a feature branch that only exists in developer environments. The CI/CD pipeline validates the thing that will actually ship — not a local approximation of it.&lt;/p&gt;

&lt;p&gt;Compare this to a model where feature branches live for days and conflicts are discovered late in the cycle. In that model, the cost of a database migration conflict is not a five-minute fix. It is a multi-day archaeological exercise involving schema diff tools, version-specific migration scripts, and at least one very uncomfortable call with a customer’s DBA.&lt;/p&gt;

&lt;p&gt;Integration latency is not just an inconvenience. In FinTech, it is direct exposure to state-level risk that compounds with every hour conflicts go undetected.&lt;/p&gt;

&lt;p&gt;There is also an underappreciated cultural benefit. When &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; is always the authoritative representation of the product — not one of several competing baselines — there is no ambiguity about what “the product” is at any moment. Engineers cannot hide behind “it works on my branch.” Either the integrated system is healthy or it isn’t. This forces the kind of engineering honesty that financial systems require.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-real-complexity-emerges-multi-customer-delivery&quot;&gt;Where Real Complexity Emerges: Multi-Customer Delivery&lt;/h2&gt;

&lt;p&gt;Now shift the lens to what the previous post addressed directly.&lt;/p&gt;

&lt;p&gt;In a multi-customer financial system, customers upgrade at different times. Each may receive a different feature set based on contractual commitments. Regulatory posture must be preserved per version. Post-delivery customizations may exist in customer environments. Schema evolution must remain upgrade-safe across every version in the field.&lt;/p&gt;

&lt;p&gt;This is not development complexity. This is delivery governance complexity. And it cannot be solved by adding more development branches.&lt;/p&gt;

&lt;p&gt;This is precisely why the branching model from the previous post is structured the way it is. Release branches are not bureaucratic overhead — they are contractual artifacts. Customer isolation branches are not fragmentation — they are version commitments made tangible. The structure exists because delivery risk in financial systems is asymmetric: a failed customer upgrade, a schema migration inconsistency, or version drift between environments carries consequences that no amount of elegant code quickly undoes.&lt;/p&gt;

&lt;p&gt;The branching model must reflect where risk truly lives. In multi-customer FinTech, risk does not primarily live in development integration. It lives in delivery.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-the-real-risk-actually-lives-release-governance&quot;&gt;Where the Real Risk Actually Lives: Release Governance&lt;/h2&gt;

&lt;p&gt;Here is the part that teams often get backwards. They introduce complex development branching to manage delivery risk — and in doing so, they delay the feedback loops that would actually help them manage it.&lt;/p&gt;

&lt;p&gt;In multi-customer FinTech, delivery risk is real and unavoidable. Your customers upgrade at different times. Some have customizations layered on top of your core product. Some operate under regulatory frameworks that require version-specific audit trails. Some have DBAs who need to sign off on every schema change before it touches their environment. This complexity exists, and no amount of trunk discipline eliminates it.&lt;/p&gt;

&lt;p&gt;But the right tool for that problem is not more development branches. It is explicit release governance. In practice, this means a clear separation of three concerns:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trunk is where you build.&lt;/strong&gt; It represents the current integrated state of the product — a state you would be comfortable deploying if a customer asked for it. Every commit is validated. Every migration is tested against upgrade paths. Every feature flag is accounted for. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt; is sacred not because of ceremony, but because every customer release is eventually cut from it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release branches are where you commit.&lt;/strong&gt; When a customer release is due, you cut a release branch from a known-good integration point on trunk. That branch represents a contractual commitment. It receives only critical fixes, applied forward from trunk. It does not receive new features. It is not a development environment — it is a delivery artifact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer branches are where you isolate.&lt;/strong&gt; In cases where a customer requires post-delivery customization or where their upgrade path diverges significantly, a customer isolation branch preserves that state explicitly. It is not where you build new things — it is where you honor existing commitments while the main product moves forward.&lt;/p&gt;

&lt;p&gt;Development complexity is managed through trunk discipline and CI/CD maturity. Delivery complexity is managed through release governance and customer isolation. These are separate concerns, and the moment you try to solve one with the tools designed for the other, you create structural debt that will surface at the worst possible moment.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;separating-development-flow-from-delivery-flow&quot;&gt;Separating Development Flow from Delivery Flow&lt;/h2&gt;

&lt;p&gt;A clean architecture makes this separation explicit, and it is what makes the overall model coherent rather than ad hoc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development&lt;/strong&gt; optimizes for clarity and speed: continuous integration into a single trunk, immediate validation of database migrations, immediate detection of integration conflicts, security baseline established at integration, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; always representing the current product state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Delivery&lt;/strong&gt; optimizes for stability and traceability: releases cut from specific validated integration points, customers receiving controlled versioned snapshots, upgrade paths tested explicitly before promotion, post-delivery isolation preserved where required by contract or regulation.&lt;/p&gt;

&lt;p&gt;When these two concerns are conflated — when teams attempt to manage delivery risk through development branching — you end up with a workflow that is simultaneously too rigid for development and too loose for delivery. The branches multiply, ownership blurs, and the actual delivery risk remains unaddressed beneath layers of process.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/designing-for-scale/development_vs_delivery_flow.svg&quot; alt=&quot;Development-Delivery flow&quot; /&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;feature-variance-across-customers-a-delivery-problem-not-a-development-one&quot;&gt;Feature Variance Across Customers: A Delivery Problem, Not a Development One&lt;/h2&gt;

&lt;p&gt;One of the hardest practical questions in multi-customer systems is what to do when a feature is not intended for every customer. The instinct is often to reach for branching — a customer-specific branch, a conditional merge, a separate integration path. This instinct is wrong, and expensive at scale.&lt;/p&gt;

&lt;p&gt;Feature variance across customers is not a development branching problem. It is a release governance problem. The correct architectural solutions are configuration-driven behavior, feature flags, or controlled release cuts from earlier integration points on trunk.&lt;/p&gt;

&lt;p&gt;The trunk represents product evolution. Release branches represent contractual commitments to specific customers at specific points in that evolution. When these concerns are kept separate, the system remains stable without fragmenting development. When they are conflated, you end up maintaining multiple divergent codebases that converge on merge complexity rather than product clarity.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;multiple-products-independent-trunks&quot;&gt;Multiple Products, Independent Trunks&lt;/h2&gt;

&lt;p&gt;When an organization operates multiple independent products, each with its own team, the model scales naturally. Each product maintains its own trunk, its own integration discipline, and its own release cadence. Cross-product coordination happens at architectural boundaries — through versioned APIs and explicit contracts — not inside Git.&lt;/p&gt;

&lt;p&gt;The temptation as organizations grow is to manage cross-product complexity through shared branching structures. That approach compounds badly. Branching complexity does not compensate for unclear system boundaries. It amplifies them.&lt;/p&gt;

&lt;p&gt;If two products cannot be maintained on independent trunks without constant cross-product branch dependencies, that is a signal that the product boundaries themselves are not real — that what has been administratively divided is architecturally unified. No branching strategy fixes an architectural boundary problem. The fix is clarifying that boundary at the code and data level.&lt;/p&gt;

&lt;p&gt;Independent trunks scale horizontally. Shared branching hierarchies scale by becoming progressively more painful until the architectural investment that should have happened earlier is finally unavoidable.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;scaling-trunk-discipline-as-teams-grow&quot;&gt;Scaling Trunk Discipline as Teams Grow&lt;/h2&gt;

&lt;p&gt;The natural objection to this model is scale: what happens when the team is no longer small?&lt;/p&gt;

&lt;p&gt;Trunk-based development does not collapse under scale. It evolves through reinforcement. What changes as teams grow is not the branch model — it is the reinforcement around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Single team:&lt;/strong&gt; Integration cost is low. Communication is immediate. Conflicts are resolved socially as much as technically. Trunk absorbs changes continuously. Simplicity is an advantage; adding integration layers adds only ceremony.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Multiple teams, single product:&lt;/strong&gt; Trunk discipline does not disappear — it hardens. Stronger CI pipelines. More granular ownership boundaries. Domain-driven modularization. Clear API contracts between internal components. Mandatory code review depth. Stricter risk classification. The branch structure remains simple. The system architecture becomes more explicit.&lt;/p&gt;

&lt;p&gt;If trunk begins to feel unstable as teams multiply, the problem is almost always architectural coupling — not the branch model itself. Trunk-based development at scale demands clear service boundaries, modular code ownership, and automated validation maturity. When those exist, trunk remains stable even as the organization grows. When they don’t, no branching complexity compensates.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/designing-for-scale/scaling_phases_arrows_fixed.svg&quot; alt=&quot;Scaling phases&quot; /&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;designing-for-scale-before-scaling--and-why-most-teams-get-this-backwards&quot;&gt;Designing for Scale Before Scaling — And Why Most Teams Get This Backwards&lt;/h2&gt;

&lt;p&gt;Here is the uncomfortable truth about engineering organizations that struggle at scale: most of them scaled their Git workflow long before they scaled their architecture. Their branching complexity is not a reflection of organizational sophistication — it is a monument to accumulated avoidance.&lt;/p&gt;

&lt;p&gt;When trunk integration becomes painful, the natural response is to add a buffer. When that buffer creates its own friction, add another layer. Before long, you have a branching hierarchy that requires a diagram to explain, an onboarding guide dedicated entirely to “how we do Git,” and senior engineers spending meaningful time just figuring out where to merge things.&lt;/p&gt;

&lt;p&gt;Conway’s Law is merciless here. Branching complexity does not fix unclear domain boundaries — it amplifies them. Every extra branch is a place where ownership becomes ambiguous. Every integration layer is an opportunity for “who’s responsible for that?” to become an unanswerable question at the worst moment.&lt;/p&gt;

&lt;p&gt;The organizations that scale well do it through architecture, not through Git ceremony. As coordination complexity genuinely increases — as teams multiply, as domains diverge, as parallel workstreams become real — the correct response is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make domain boundaries explicit in the code.&lt;/strong&gt; Module ownership should be unambiguous. Internal APIs should be formal, not informal. Shared state should be minimal and clearly governed. When boundaries are real, trunk integration stays stable even as the team grows, because changes to one domain don’t silently break another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deepen CI/CD, don’t widen branching.&lt;/strong&gt; A mature CI/CD pipeline — one that runs comprehensive migration testing, contract validation, security scanning, and regression testing on every commit — eliminates most rationale for staging buffers. The staging function moves into automation, where it belongs.&lt;/p&gt;

&lt;p&gt;The evolution path is clear:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Stage&lt;/th&gt;
      &lt;th&gt;Response&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Small team&lt;/td&gt;
      &lt;td&gt;Simplicity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Growing team&lt;/td&gt;
      &lt;td&gt;Reinforced simplicity&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Large organization&lt;/td&gt;
      &lt;td&gt;Architectural segmentation&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;At no point is the answer “add more permanent branches.” Branching complexity should follow demonstrated organizational necessity — not anticipate it prematurely. Premature complexity becomes structural debt, and structural debt in delivery pipelines compounds faster than technical debt in code.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-economic-frame-why-this-is-a-capital-allocation-question-not-a-tooling-one&quot;&gt;The Economic Frame: Why This Is a Capital Allocation Question, Not a Tooling One&lt;/h2&gt;

&lt;p&gt;Engineering leaders in FinTech sometimes resist thinking about software development structure in economic terms. That resistance is expensive.&lt;/p&gt;

&lt;p&gt;Every structural decision in your delivery pipeline has a cost and a yield. Integration latency has a cost: the longer conflicts go undetected, the more expensive they are to resolve. Fragmented baselines have a cost: cognitive overhead multiplied across every engineer who needs to understand where things actually stand. Unclear release state has a cost: compliance exposure, customer confusion, and the engineering time spent answering “wait, what version is this customer actually on?”&lt;/p&gt;

&lt;p&gt;Database migration failures in production have a cost that is easy to underestimate until you have lived through one: direct customer downtime, potential data inconsistency, compliance review, customer success escalations, and a rebuild of trust that takes months. Preventing one of those with better integration discipline and more explicit release governance is an extremely high-ROI investment.&lt;/p&gt;

&lt;p&gt;Conversely, premature branching complexity also has a cost. Every permanent integration layer is an ongoing tax on developer velocity and cognitive bandwidth. Every merge ceremony that exists without clear organizational justification is waste — not disciplined waste, just waste.&lt;/p&gt;

&lt;p&gt;The economically rational structure for a single-team FinTech product with multi-customer delivery obligations is not complicated to state:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Trunk discipline for building&lt;/strong&gt; — one authoritative baseline, continuous integration, forward-fix culture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Release branching for distribution&lt;/strong&gt; — controlled snapshots, contractual commitments, upgrade-path validation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Customer isolation where necessary&lt;/strong&gt; — post-delivery preservation of contractual state without fragmenting development&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nothing more. Nothing less. The goal is minimal structural complexity commensurate with actual organizational reality.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-subtle-but-important-shift-in-perspective&quot;&gt;A Subtle but Important Shift in Perspective&lt;/h2&gt;

&lt;p&gt;Most teams design branching models around what might go wrong. They add gates and buffers reactively, in response to past incidents or imagined future complexity.&lt;/p&gt;

&lt;p&gt;A more resilient approach is designing around where things actually are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Where does state persist?&lt;/li&gt;
  &lt;li&gt;Where are version commitments made?&lt;/li&gt;
  &lt;li&gt;Where does coordination truly exist?&lt;/li&gt;
  &lt;li&gt;Where does operational risk concentrate?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the systems this series has been describing, the answer is consistent: development risk is low, delivery risk is high. So the correct response is to optimize development for clarity and speed, and optimize delivery for governance and traceability.&lt;/p&gt;

&lt;p&gt;That is what the branching model from the previous post implements in practice. This post has argued why it is the right model — not because of aesthetic preference for simplicity, but because it honestly reflects where complexity lives in the organization.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;closing-thought&quot;&gt;Closing Thought&lt;/h2&gt;

&lt;p&gt;The goal is not to defend trunk-based development as an ideology. The goal is to align the delivery model with organizational reality — today and as the organization grows.&lt;/p&gt;

&lt;p&gt;Today, if development complexity is low and delivery complexity is high, the structure should reflect that honestly. Tomorrow, as development complexity genuinely increases, the model evolves — through stronger architecture, deeper automation, explicit domain separation, and temporary orchestration when necessary. Not through permanent branching layers that accumulate as artifacts of decisions made under pressure.&lt;/p&gt;

&lt;p&gt;Simplicity is not fragile.&lt;br /&gt;
It is scalable — when reinforced intentionally and when it honestly mirrors the organization that maintains it.&lt;/p&gt;

&lt;p&gt;Structure is not aesthetics.&lt;br /&gt;
In FinTech, it is economics.&lt;br /&gt;
And economic misalignment compounds faster than code complexity ever will.&lt;/p&gt;
</description>
        <pubDate>Sun, 15 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/03/15/Designing-for-scale/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/03/15/Designing-for-scale/</guid>
      </item>
    
      <item>
        <title>The Inevitable Cycles: Why Software Houses Keep Returning to Square One</title>
        <description>&lt;h2 id=&quot;there-and-back-again--from-cloud-to-on-prem-projects-to-products&quot;&gt;There and Back Again — from Cloud to On-Prem, Projects to Products&lt;/h2&gt;

&lt;p&gt;Software organizations do not scale by following a single best practice indefinitely. Decisions that enable speed and survival in early stages—cloud-first infrastructure, project-driven delivery, lightweight processes, and generalist roles—often become sources of friction as teams, customers, and systems grow. What appears to be a return to “square one” is rarely regression; it is a recalibration driven by new economic, operational, and organizational realities. Much like a journey there and back again, experienced software leaders recognize that sustainable growth depends on knowing when to revisit earlier choices—not to repeat them, but to apply them with greater discipline and intent.&lt;/p&gt;

&lt;p&gt;The diagram below summarizes the recurring cycles discussed throughout this article.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/software-evolution/five-cycles.png&quot; alt=&quot;Diagram showing five recurring cycles in software house evolution — infrastructure, delivery model, process, roles, technical debt&quot; /&gt;
&lt;em&gt;Five recurring cycles in software organization evolution&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;cloud-vs-on-prem-infrastructure-evolution&quot;&gt;Cloud vs On-Prem Infrastructure Evolution&lt;/h1&gt;

&lt;p&gt;The first place this cyclical pattern becomes visible is infrastructure. Few decisions feel as definitive—or as emotionally charged—as the choice between cloud and on-prem. Yet across startups, scale-ups, and mature software houses, infrastructure strategy repeatedly follows the same arc: cloud first, then self-hosted, and eventually back to cloud again. This pattern is not anecdotal; it is repeatedly observed in academic research and industry surveys examining long-term cost structures, operational complexity, and organizational maturity.&lt;/p&gt;

&lt;h2 id=&quot;phase-1--startup-mode-cloud-first-by-necessity&quot;&gt;Phase 1 — Startup Mode: Cloud-First by Necessity&lt;/h2&gt;

&lt;p&gt;In the earliest stage, infrastructure decisions are driven almost entirely by survival. Small teams—typically between two and twenty engineers—default to cloud-hosted tooling such as GitHub or GitLab SaaS, managed CI/CD pipelines, hosted issue trackers, and fully managed databases.&lt;/p&gt;

&lt;p&gt;This choice is pragmatic rather than strategic. Cloud platforms eliminate upfront capital expenditure, require minimal DevOps maturity, and allow teams to focus on shipping features instead of running systems. Industry analyses consistently show that startups favor cloud infrastructure because it converts capital expenses into operating expenses and dramatically reduces time-to-market &lt;a href=&quot;#ref-1&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this stage, unit economics and long-term total cost of ownership are secondary concerns. Speed, optionality, and survival dominate decision-making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud, here, is less a strategy and more a survival hack.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;phase-2--growth-mode-when-cloud-becomes-quietly-expensive&quot;&gt;Phase 2 — Growth Mode: When Cloud Becomes “Quietly Expensive”&lt;/h2&gt;

&lt;p&gt;As organizations grow into the 20–200 engineer range, the economics begin to shift. What once felt frictionless starts to reveal hidden costs. CI minutes grow exponentially, storage and artifact repositories expand rapidly, and per-user SaaS pricing compounds across teams. Compliance, data residency, and security requirements introduce constraints that were irrelevant in the startup phase.&lt;/p&gt;

&lt;p&gt;This is typically the point where finance begins questioning infrastructure spend: &lt;strong&gt;Why is our tooling cost growing faster than revenue?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In response, engineering teams often start self-hosting parts of the stack—Git servers, CI runners, artifact repositories—because steady, predictable workloads make on-premise or self-managed infrastructure appear financially attractive. This perception is supported by both academic and industry research. Fisher (2018) &lt;a href=&quot;#ref-2&quot;&gt;[2]&lt;/a&gt; demonstrates that while cloud solutions are cheaper in early years, on-premise infrastructure can be significantly less expensive over long time horizons, with total costs dropping to nearly 56% of cloud costs after ten years for stable workloads.&lt;/p&gt;

&lt;p&gt;Industry cost analyses and practitioner reports reinforce this finding, particularly where utilization is high and elasticity offers limited benefit &lt;a href=&quot;#ref-3&quot;&gt;[3]&lt;/a&gt;&lt;a href=&quot;#ref-4&quot;&gt;[4]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At this stage, moving away from the cloud is often seen as a sign of maturity—a correction to early convenience-driven decisions.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;phase-3--scale-mode-operational-complexity-takes-over&quot;&gt;Phase 3 — Scale Mode: Operational Complexity Takes Over&lt;/h2&gt;

&lt;p&gt;As software houses scale further—beyond 200 engineers or across multiple business units—the dominant constraint shifts again. This time, it is no longer primarily about infrastructure cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational complexity becomes the real bottleneck.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Self-hosted systems proliferate: version control, CI/CD, wikis, ticketing platforms, monitoring stacks, identity systems. Each requires upgrades, backups, disaster recovery planning, security patching, and dedicated operational ownership. Over time, specialized teams emerge whose primary responsibility is simply keeping internal platforms running, while critical knowledge becomes concentrated in small silos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At this scale, cognitive load and organizational risk outweigh raw infrastructure savings.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where the pendulum swings back. Mature organizations increasingly return to cloud platforms—not to reduce costs, but to simplify governance and reduce operational drag. Large-scale surveys and enterprise studies show that most organizations eventually adopt hybrid models, combining on-prem and cloud workloads to balance cost efficiency, compliance, and operational resilience &lt;a href=&quot;#ref-5&quot;&gt;[5]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud, at this stage, is no longer about speed. It becomes a governance and complexity management tool.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; The recurring cloud-to-on-prem-and-back cycle reveals a deeper truth: infrastructure cost is rarely the root problem—organizational complexity is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As teams grow, the “right” infrastructure choice changes—not because earlier decisions were wrong, but because scale fundamentally alters the optimization landscape &lt;a href=&quot;#ref-6&quot;&gt;[6]&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;project-to-product-evolution&quot;&gt;Project-to-Product Evolution&lt;/h1&gt;

&lt;p&gt;A second, equally persistent cycle appears in how software houses deliver value. Many organizations begin by building bespoke solutions for individual customers, evolve toward productization to gain leverage, and eventually find themselves constrained by the very products that once enabled their growth. This pattern is not anecdotal; it is well documented in both academic research and industry practice examining how software firms transition from customer-specific development to market-oriented product models.&lt;/p&gt;

&lt;h2 id=&quot;phase-1--project-driven-beginnings&quot;&gt;Phase 1 — Project-Driven Beginnings&lt;/h2&gt;

&lt;p&gt;Most software houses start as project-driven organizations. Early teams build exactly what customers ask for, optimize for delivery speed, and tie revenue directly to individual engagements. This approach provides immediate benefits: fast cash flow, deep customer understanding, and highly adaptable engineering teams.&lt;/p&gt;

&lt;p&gt;Academic research describes this phase as customer-specific software development, where solutions are tightly coupled to individual clients rather than a broader market &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;. For young companies, this model is not a weakness—it is a rational response to uncertainty, allowing teams to learn quickly and establish credibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The limitations emerge gradually.&lt;/strong&gt; Each project largely starts from zero, reuse is minimal, and scale is achieved primarily by adding people. Engineering leverage remains low, and margins are constrained by delivery capacity.&lt;/p&gt;

&lt;h2 id=&quot;phase-2--productization-for-leverage&quot;&gt;Phase 2 — Productization for Leverage&lt;/h2&gt;

&lt;p&gt;As similar projects repeat, patterns begin to emerge. Teams identify common components, shared architectures take shape, and internal frameworks evolve into platforms. Over time, this reuse becomes intentional, and a product is born.&lt;/p&gt;

&lt;p&gt;This transition—from bespoke projects to product software—is formally described in the software engineering literature as &lt;strong&gt;productization&lt;/strong&gt; &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;&lt;a href=&quot;#ref-8&quot;&gt;[8]&lt;/a&gt;. Empirical case studies show organizations moving through identifiable stages: independent projects, reuse across projects, product recognition, and eventually product platforms &lt;a href=&quot;#ref-7&quot;&gt;[7]&lt;/a&gt;. As companies progress through these stages, they introduce software product management practices such as roadmapping, release planning, and market-driven requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The benefits are significant.&lt;/strong&gt; Productization enables reuse, predictable delivery, improved margins, and sales scalability. This is the point at which many software houses begin operating as product companies rather than service providers.&lt;/p&gt;

&lt;p&gt;Industry perspectives reinforce this shift. Mik Kersten’s Project to Product frames this evolution as a move away from funding individual projects toward optimizing value streams, enabling organizations to scale delivery without scaling headcount at the same rate &lt;a href=&quot;#ref-9&quot;&gt;[9]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-3--product-maturity-becomes-rigidity&quot;&gt;Phase 3 — Product Maturity Becomes Rigidity&lt;/h2&gt;

&lt;p&gt;Over time, mature products tend to harden. Architectures stabilize, customization paths narrow, and change becomes slower and more expensive. What once enabled scale begins to constrain flexibility.&lt;/p&gt;

&lt;p&gt;At this stage, customers increasingly seek differentiation, faster turnaround, and workflows tailored to their specific needs. Instead, they often hear:
&lt;strong&gt;That’s not supported—you’ll need to adapt your process to the product.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Research on evolving software product lines highlights this tension explicitly. As products mature, customization becomes more complex and costly, particularly when variability was not designed into the architecture early on &lt;a href=&quot;#ref-10&quot;&gt;[10]&lt;/a&gt;. Consulting research reaches a similar conclusion: firms that over-standardize often struggle to balance customization value against the operational cost of complexity &lt;a href=&quot;#ref-11&quot;&gt;[11]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The outcome is predictable. Some customers drift away, and new software houses emerge offering bespoke solutions once again. The cycle restarts—not because productization failed, but because no single delivery model optimizes for both scale and differentiation indefinitely.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Products optimize for scale. Bespoke solutions optimize for differentiation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;No single model wins forever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project-to-product cycle is not a linear maturity path with a final destination—it is a recurring recalibration driven by changing market, customer, and organizational constraints.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;process-evolution&quot;&gt;Process Evolution&lt;/h1&gt;

&lt;p&gt;The cyclical nature of software organizations becomes especially visible in how delivery processes evolve. Over the past several decades, teams have repeatedly shifted from structured, plan-driven models to lighter, iterative approaches—only to later reintroduce structure in new forms. This evolution is not random; it reflects how organizations respond to changing scale, risk, and coordination challenges &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;&lt;a href=&quot;#ref-13&quot;&gt;[13]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-1--structured-processes-for-predictability&quot;&gt;Phase 1 — Structured Processes for Predictability&lt;/h2&gt;

&lt;p&gt;Early large-scale software efforts favored highly &lt;strong&gt;structured&lt;/strong&gt;, sequential models such as Waterfall. These approaches emphasized upfront planning, documentation, and formal handoffs in an attempt to control complexity and risk. Historically, this model was particularly attractive to regulated industries and large institutions, including government and defense organizations &lt;a href=&quot;#ref-14&quot;&gt;[14]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At smaller scales, this structure often proved heavy-handed. Long feedback cycles delayed learning, and teams struggled to adapt to changing requirements. As markets accelerated and software became more customer-facing, the limitations of rigid, upfront planning became increasingly visible.&lt;/p&gt;

&lt;h2 id=&quot;phase-2--agile-and-devops-as-a-reaction-to-rigidity&quot;&gt;Phase 2 — Agile and DevOps as a Reaction to Rigidity&lt;/h2&gt;

&lt;p&gt;Agile methodologies emerged as a direct response to the constraints of plan-heavy processes. By prioritizing working software, short feedback loops, and close collaboration, Agile promised speed, adaptability, and higher customer satisfaction. Later, DevOps extended this thinking by &lt;strong&gt;integrating development and operations&lt;/strong&gt;, reducing deployment friction, and improving delivery throughput &lt;a href=&quot;#ref-12&quot;&gt;[12]&lt;/a&gt;&lt;a href=&quot;#ref-15&quot;&gt;[15]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Large-scale industry studies, including DevOps maturity and performance research, show that these practices deliver substantial benefits when adopted effectively. Teams report faster deployment cycles, improved reliability, and stronger alignment between technical and business outcomes &lt;a href=&quot;#ref-15&quot;&gt;[15]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, as Agile and DevOps scaled across entire organizations, new problems surfaced. Coordination across multiple teams, regulatory compliance, dependency management, and long-term planning reintroduced complexity. What began as a lightweight process often accumulated layers of ceremony, tooling, and governance—ironically recreating some of the rigidity Agile originally sought to eliminate.&lt;/p&gt;

&lt;h2 id=&quot;phase-3--hybrid-models-and-the-return-of-structure&quot;&gt;Phase 3 — Hybrid Models and the Return of Structure&lt;/h2&gt;

&lt;p&gt;At scale, many organizations do not abandon Agile—but they adapt it. Hybrid delivery models emerge, blending Agile practices with traditional planning and governance mechanisms. Research and industry case studies consistently show large enterprises combining Waterfall-style stage gates with Agile execution to manage risk, especially where legacy systems or regulatory constraints exist &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;&lt;a href=&quot;#ref-17&quot;&gt;[17]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Professional bodies such as the Project Management Institute (PMI) explicitly acknowledge this trend, noting that successful organizations are not choosing between Agile and Waterfall permanently, but intentionally blending them based on context &lt;a href=&quot;#ref-16&quot;&gt;[16]&lt;/a&gt;. Peer-reviewed research reinforces this view, identifying hybrid models as an increasingly common and effective response to competing demands for predictability and flexibility &lt;a href=&quot;#ref-18&quot;&gt;[18]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The result is a familiar pattern: organizations move from rigid structure to flexibility, then reintroduce structure—this time informed by experience and adapted to scale.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Process evolution in software organizations is not a linear progression toward a “best” methodology.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Processes are adopted to solve today’s dominant problems—speed, quality, coordination—but each solution introduces new constraints at scale. As those constraints grow, organizations adjust again, often revisiting earlier ideas in modified form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What looks like regression is usually recalibration.&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;role-evolution-cycle&quot;&gt;Role Evolution Cycle&lt;/h1&gt;

&lt;p&gt;As software organizations scale, the way roles are defined and organized evolves in predictable—and recurring—patterns. Early teams favor generalists who &lt;strong&gt;do everything.&lt;/strong&gt; Growth introduces specialization to reduce risk and increase reliability. At larger scales, however, specialization itself becomes a bottleneck, driving organizations back toward integrated, cross-functional or platform-oriented team models. This evolution is not linear; it is cyclical, shaped by tooling maturity, organizational friction, and delivery constraints &lt;a href=&quot;#ref-19&quot;&gt;[19]&lt;/a&gt;&lt;a href=&quot;#ref-20&quot;&gt;[20]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-1--generalists-by-necessity&quot;&gt;Phase 1 — Generalists by Necessity&lt;/h2&gt;

&lt;p&gt;In early-stage software teams, roles are fluid. Developers write code, deploy it, debug production issues, and often interact directly with customers. This generalist model is not ideological—it is practical. Small teams lack the scale to support specialized roles, and modern tooling lowers the barrier to participating across the delivery lifecycle.&lt;/p&gt;

&lt;p&gt;Industry commentary on role evolution notes that early engineers are often “full-stack by default,” covering wide functional areas out of necessity rather than preference &lt;a href=&quot;#ref-21&quot;&gt;[21]&lt;/a&gt;. At this stage, autonomy is high, coordination overhead is low, and speed matters more than formal role boundaries.&lt;/p&gt;

&lt;h2 id=&quot;phase-2--specialization-to-manage-scale&quot;&gt;Phase 2 — Specialization to Manage Scale&lt;/h2&gt;

&lt;p&gt;As systems grow more complex and uptime expectations increase, organizations introduce specialization. Dedicated roles emerge: DevOps engineers, SREs, QA specialists, security engineers, and release managers. Each role addresses a real scaling pain—deployment failures, operational instability, quality regressions, or compliance risk.&lt;/p&gt;

&lt;p&gt;Google’s Site Reliability Engineering (SRE) model is a canonical example of this phase. SRE reframed operations as an engineering discipline, introducing explicit reliability targets, automation, and error budgets to manage production risk at scale &lt;a href=&quot;#ref-19&quot;&gt;[19]&lt;/a&gt;. Similarly, DevOps practices formalized responsibilities that were previously implicit, creating clearer ownership and accountability.&lt;/p&gt;

&lt;p&gt;Academic research on Agile and DevOps transitions supports this pattern, showing that role differentiation often accompanies process and tooling maturity as organizations attempt to stabilize delivery and reduce operational risk &lt;a href=&quot;#ref-22&quot;&gt;[22]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-3--specialization-becomes-friction&quot;&gt;Phase 3 — Specialization Becomes Friction&lt;/h2&gt;

&lt;p&gt;Over time, specialization introduces its own costs. Handoffs multiply, feedback loops slow, and ownership becomes fragmented. Developers wait on other teams to deploy, debug, or provision environments. &lt;strong&gt;Throw it over the wall&lt;/strong&gt; dynamics quietly reappear—this time between internal specialists rather than departments.&lt;/p&gt;

&lt;p&gt;Industry analyses of DevOps and role maturity repeatedly note this inflection point. As organizations add more specialized roles, coordination overhead increases and local optimizations begin to harm end-to-end flow &lt;a href=&quot;#ref-20&quot;&gt;[20]&lt;/a&gt;&lt;a href=&quot;#ref-23&quot;&gt;[23]&lt;/a&gt;. The very roles created to improve delivery now constrain it.&lt;/p&gt;

&lt;p&gt;This pressure drives a structural shift.&lt;/p&gt;

&lt;h2 id=&quot;phase-4--recomposition-into-cross-functional-and-platform-teams&quot;&gt;Phase 4 — Recomposition into Cross-Functional and Platform Teams&lt;/h2&gt;

&lt;p&gt;To reduce friction, organizations reorganize again—this time recomposing roles into cross-functional product teams or platform teams that internalize operational responsibility. Instead of central DevOps or SRE teams acting as gatekeepers, platforms provide paved roads, and product teams regain autonomy within guardrails.&lt;/p&gt;

&lt;p&gt;This shift aligns with the rise of T-shaped engineers—individuals with deep expertise in one area and sufficient breadth to collaborate effectively across disciplines &lt;a href=&quot;#ref-24&quot;&gt;[24]&lt;/a&gt;&lt;a href=&quot;#ref-25&quot;&gt;[25]&lt;/a&gt;. Modern automation, cloud platforms, and AI-assisted tooling further lower the cost of recombining responsibilities, enabling teams to operate with fewer handoffs than before.&lt;/p&gt;

&lt;p&gt;Historical analyses of role evolution explicitly document this pendulum: specialist-heavy models solve scaling problems, then give way to integrated team structures once coordination becomes the dominant bottleneck &lt;a href=&quot;#ref-20&quot;&gt;[20]&lt;/a&gt;&lt;a href=&quot;#ref-24&quot;&gt;[24]&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Role evolution in software organizations is a balancing act between autonomy and stability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Organizations oscillate between generalists and specialists not because one model is superior, but because each solves a different scaling problem—and creates the next one.&lt;/p&gt;

&lt;p&gt;What appears to be a return to earlier role models is usually a recomposition informed by better tooling, clearer boundaries, and hard-earned experience.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;technical-debt-accumulation-curve&quot;&gt;Technical Debt Accumulation Curve&lt;/h1&gt;

&lt;p&gt;Among all the cycles software organizations experience, technical debt is the most persistent—and the most misunderstood. Teams knowingly incur it to move fast, struggle under its weight as systems grow, and eventually face a reckoning: &lt;strong&gt;invest in sustained remediation or attempt a risky rebuild&lt;/strong&gt; &lt;a href=&quot;#ref-26&quot;&gt;[26]&lt;/a&gt;&lt;a href=&quot;#ref-27&quot;&gt;[27]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-1--intentional-debt-in-the-name-of-speed&quot;&gt;Phase 1 — Intentional Debt in the Name of Speed&lt;/h2&gt;

&lt;p&gt;The concept of technical debt was originally articulated by Ward Cunningham to describe the trade-off between rapid delivery and long-term code quality. Like financial debt, it allows teams to move faster in the short term, with the expectation that the cost will be paid back later &lt;a href=&quot;#ref-26&quot;&gt;[26]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In early-stage products and startups, this trade-off is often rational. Delivery pressure, limited resources, and uncertain requirements incentivize shortcuts: hard-coded assumptions, minimal abstractions, deferred refactoring, and sparse documentation. Empirical research confirms that startups accumulate disproportionately higher levels of technical debt due to these constraints &lt;a href=&quot;#ref-28&quot;&gt;[28]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this stage, debt is largely invisible. Velocity remains high, and the system still &lt;strong&gt;fits in the team’s head.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;phase-2--growth-turns-debt-into-drag&quot;&gt;Phase 2 — Growth Turns Debt into Drag&lt;/h2&gt;

&lt;p&gt;As the codebase grows and teams expand, technical debt stops being theoretical. Changes take longer, defects increase, and onboarding new engineers becomes expensive. What was once a local shortcut becomes a systemic constraint.&lt;/p&gt;

&lt;p&gt;Recent empirical studies show that technical debt grows non-linearly as projects evolve, significantly increasing future development effort and complexity &lt;a href=&quot;#ref-27&quot;&gt;[27]&lt;/a&gt;. Longitudinal analyses of issue trackers and repositories reveal that technical debt items often remain unresolved for long periods, accumulating interest in the form of slower delivery and higher defect rates &lt;a href=&quot;#ref-29&quot;&gt;[29]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this stage, organizations typically respond with refactoring initiatives, architectural cleanups, or &lt;strong&gt;modernization programs.&lt;/strong&gt; These efforts reduce debt temporarily—but rarely eliminate it entirely.&lt;/p&gt;

&lt;h2 id=&quot;phase-3--rewrite-temptation-and-the-point-of-no-return&quot;&gt;Phase 3 — Rewrite Temptation and the Point of No Return&lt;/h2&gt;

&lt;p&gt;When incremental remediation no longer feels sufficient, teams begin discussing the ultimate reset: a rewrite from scratch.&lt;/p&gt;

&lt;p&gt;History shows that this moment recurs across generations of software companies. The late 1990s Netscape rewrite, famously chronicled by Joel Spolsky, established the industry’s early doctrine: &lt;strong&gt;never rewrite your software&lt;/strong&gt; &lt;a href=&quot;#ref-30&quot;&gt;[30]&lt;/a&gt;. Subsequent decades reinforced this cautionary stance as many large-scale rewrites failed spectacularly—often due to underestimated scope, shifting requirements, or organizational fragmentation &lt;a href=&quot;#ref-31&quot;&gt;[31]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yet the story is not one-sided. Some organizations have successfully rewritten major systems under specific conditions: strong executive alignment, disciplined scope control, and long-term investment. Case studies from companies such as Basecamp, Adobe, and Microsoft (VS Code) demonstrate that &lt;strong&gt;rewrites can succeed&lt;/strong&gt;—but only when treated as strategic, organization-wide commitments rather than engineering side projects &lt;a href=&quot;#ref-32&quot;&gt;[32]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Empirical and consulting research suggests that most rewrites fail not because rewriting is inherently wrong, but because technical debt is a symptom of deeper organizational and process issues that rewriting alone does not solve &lt;a href=&quot;#ref-33&quot;&gt;[33]&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;phase-4--debt-re-accumulates-under-new-pressures&quot;&gt;Phase 4 — Debt Re-accumulates Under New Pressures&lt;/h2&gt;

&lt;p&gt;Even successful rewrites do not end the cycle. New architectures introduce new assumptions. Market pressure returns. Teams optimize for speed again.&lt;/p&gt;

&lt;p&gt;McKinsey research estimates that technical debt accounts for &lt;strong&gt;20–40%&lt;/strong&gt; of the value of the entire technology estate, with a majority of CIOs reporting that debt continues to rise year over year &lt;a href=&quot;#ref-34&quot;&gt;[34]&lt;/a&gt;. This creates renewed pressure for shortcuts—and the cycle begins again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical debt, in practice, is not a problem to be solved once. It is a force to be continuously managed.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Technical debt behaves like a lifecycle, not a defect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Teams incur it intentionally to deliver value quickly, suffer its consequences as systems scale, and periodically attempt to reset through refactoring or rebuilds. The pattern repeats not because teams fail to learn—but because growth, competition, and time-to-market pressures never disappear.&lt;/p&gt;

&lt;p&gt;The real differentiator is not whether an organization accumulates technical debt, but whether it builds the discipline to service it continuously.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;conclusion-cycles-as-a-source-of-strength&quot;&gt;Conclusion: Cycles as a Source of Strength&lt;/h1&gt;

&lt;p&gt;Software organizations do not struggle because they revisit earlier decisions; they struggle when they expect growth to be linear and permanent answers to exist. The patterns explored here—shifting infrastructure strategies, moving between projects and products, evolving processes, redefining roles, and accumulating technical debt—are not signs of confusion or failure. They are predictable responses to changing constraints as organizations scale.&lt;/p&gt;

&lt;p&gt;Each phase in these cycles solves a real problem. Cloud platforms enable speed before cost and governance matter. Productization creates leverage before differentiation becomes critical. Agile and DevOps improve flow before coordination and control dominate. Specialized roles stabilize systems before silos slow them down. Technical debt accelerates delivery before it compounds into drag. None of these choices are inherently wrong. They become problematic only when treated as final destinations rather than context-dependent tools.&lt;/p&gt;

&lt;p&gt;At its core, this is a story of continuous improvement rather than straight-line progress. Agile, in its original sense, is not a set of ceremonies or frameworks but a mindset grounded in feedback, learning, and adaptation. Organizations that endure are not those that avoid cycles, but those that move through them deliberately—recognizing when yesterday’s strengths have become today’s constraints, and adjusting without thrashing or denial.&lt;/p&gt;

&lt;p&gt;In evolutionary terms, survival favors not the strongest or the most sophisticated, but the most adaptable. Software houses that persist are rarely the ones with the most advanced tooling or the most rigidly enforced processes. They are the ones that develop judgment—knowing when to standardize and when to customize, when to centralize and when to empower, when to pay down debt and when to accept it consciously.&lt;/p&gt;

&lt;p&gt;Much like There and Back Again, the journey matters less for where it begins or ends than for what is learned along the way. Bilbo returns from his first adventure not simply changed, but prepared—better equipped to recognize danger, make decisions, and navigate uncertainty when the next challenge arrives. Software organizations follow the same path. Each cycle, when navigated intentionally, leaves them wiser and more capable than before.&lt;/p&gt;

&lt;p&gt;Progress in software is rarely about finding the right final state. It is about building the ability to return—again and again—with greater understanding, sharper judgment, and the resilience to face whatever comes next.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;sources--further-reading&quot;&gt;Sources &amp;amp; Further Reading&lt;/h2&gt;

&lt;p&gt;&lt;a id=&quot;ref-1&quot;&gt;&lt;/a&gt;
[1] &lt;a href=&quot;https://www.sosuvconsulting.com/post/selecting-best-option-for-startups-on-premises-vs-cloud-solutions&quot;&gt;&lt;strong&gt;Sosuv Consulting&lt;/strong&gt; — &lt;em&gt;Selecting the Best Option for Startups: On-Premises vs Cloud Solutions&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Explores why startups overwhelmingly choose cloud early on and why those decisions are often revisited as organizations scale.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-2&quot;&gt;&lt;/a&gt;
[2] &lt;a href=&quot;https://www.scirp.org/journal/paperinformation?paperid=87661&quot;&gt;&lt;strong&gt;Cameron Fisher (2018)&lt;/strong&gt; — &lt;em&gt;Cloud versus On-Premise Computing&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
American Journal of Industrial and Business Management.&lt;br /&gt;
A detailed total cost of ownership (TCO) analysis showing how cloud solutions can be cheaper initially but significantly more expensive than on-premise infrastructure over long, stable usage periods.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-3&quot;&gt;&lt;/a&gt;
[3] &lt;a href=&quot;https://www.computerweekly.com/feature/Reverse-cloud-migrations-Why-some-enterprises-are-shifting-their-IT-back-on-premise&quot;&gt;&lt;strong&gt;Computer Weekly&lt;/strong&gt; — &lt;em&gt;Reverse cloud migrations: Why some enterprises are shifting their IT back on-premise&lt;/em&gt;&lt;/a&gt;
Reports on IDC survey data showing a significant percentage of enterprises planning partial or full cloud reversals.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-4&quot;&gt;&lt;/a&gt;
[4] &lt;a href=&quot;https://campustechnology.com/articles/2024/09/30/are-organizations-moving-from-cloud-to-on-premises.aspx&quot;&gt;&lt;strong&gt;Campus Technology (September 2024)&lt;/strong&gt; — &lt;em&gt;Are Organizations Moving from Cloud to On-Premises?&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Cites a Citrix study indicating that many organizations are reconsidering cloud-first strategies.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-5&quot;&gt;&lt;/a&gt;
[5] &lt;a href=&quot;https://terrazone.io/on-prem-vs-cloud-tco/&quot;&gt;&lt;strong&gt;Terrazone&lt;/strong&gt; — &lt;em&gt;On-Prem vs Cloud: Total Cost of Ownership (TCO)&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Comparative analysis emphasizing scenarios where predictable workloads favor self-managed infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-6&quot;&gt;&lt;/a&gt;
[6] &lt;a href=&quot;https://my.idc.com/getdoc.jsp?containerId=prAP53785525&quot;&gt;&lt;strong&gt;IDC (Industry Surveys)&lt;/strong&gt; — &lt;em&gt;Hybrid Cloud Adoption Trends&lt;/em&gt;&lt;/a&gt;
IDC research showing most enterprises operate hybrid environments as they mature.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-7&quot;&gt;&lt;/a&gt;
[7] &lt;a href=&quot;https://www.researchgate.net/publication/286214596_Transforming_to_Product_Software_The_Evolution_of_Software_Product_Management_Processes_during_the_Stages_of_Productization&quot;&gt;&lt;strong&gt;Leenen et al. (2012)&lt;/strong&gt; — &lt;em&gt;Transforming to Product Software: The Evolution of Software Product Management Processes&lt;/em&gt;&lt;/a&gt;
Springer / Utrecht University.&lt;br /&gt;
Foundational academic study on software productization stages.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-8&quot;&gt;&lt;/a&gt;
[8] &lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-3-642-13633-7_8&quot;&gt;&lt;strong&gt;Artz, van de Weerd, Brinkkemper (2010)&lt;/strong&gt; — &lt;em&gt;Productization: Transforming from Developing Customer-Specific Software to Product Software&lt;/em&gt;&lt;/a&gt;
Classic academic framing of the project-to-product transition.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-9&quot;&gt;&lt;/a&gt;
[9] &lt;a href=&quot;https://itrevolution.com/articles/project-to-product-mik-kersten/&quot;&gt;&lt;strong&gt;Mik Kersten (2019)&lt;/strong&gt; — &lt;em&gt;Project to Product&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Industry perspective on shifting from project funding to value-stream optimization.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-10&quot;&gt;&lt;/a&gt;
[10] &lt;a href=&quot;https://link.springer.com/article/10.1007/s10664-021-10101-6&quot;&gt;&lt;strong&gt;Empirical Software Engineering (2022)&lt;/strong&gt; — &lt;em&gt;Visualizing the Customization Endeavor in Product-Based Software&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Academic research on customization challenges in mature software products.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-11&quot;&gt;&lt;/a&gt;
[11] &lt;a href=&quot;https://www.strategy-business.com/article/04104&quot;&gt;&lt;strong&gt;Strategy+Business (Booz Allen Hamilton)&lt;/strong&gt; — &lt;em&gt;Smart Customization: Profitable Growth Through Tailored Business Streams&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Research on balancing customization value against complexity costs.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-12&quot;&gt;&lt;/a&gt;
[12] &lt;a href=&quot;https://xorbix.com/insights/the-evolution-of-software-development-methodologies/&quot;&gt;&lt;strong&gt;Xorbix&lt;/strong&gt; — &lt;em&gt;The Evolution of Software Development Methodologies&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
High-level overview of Waterfall → Agile → DevOps evolution.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-13&quot;&gt;&lt;/a&gt;
[13] &lt;a href=&quot;https://en.wikipedia.org/wiki/Lehman%27s_laws_of_software_evolution&quot;&gt;&lt;strong&gt;Lehman, M. M.&lt;/strong&gt; — &lt;em&gt;Laws of Software Evolution&lt;/em&gt;&lt;/a&gt;
Foundational theory describing software systems and processes as feedback-driven systems.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-14&quot;&gt;&lt;/a&gt;
[14] &lt;a href=&quot;https://en.wikipedia.org/wiki/Waterfall_model&quot;&gt;&lt;strong&gt;Wikipedia&lt;/strong&gt; — &lt;em&gt;Waterfall Model&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Documents institutional use and later evolution toward iterative models.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-15&quot;&gt;&lt;/a&gt;
[15] &lt;a href=&quot;https://cloud.google.com/devops/state-of-devops&quot;&gt;&lt;strong&gt;Google Cloud / DORA&lt;/strong&gt; — &lt;em&gt;State of DevOps Reports&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Large-scale industry research on DevOps maturity and organizational evolution.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-16&quot;&gt;&lt;/a&gt;
[16] &lt;a href=&quot;https://www.pmi.org/learning/library/blending-agile-waterfall-successful-integration-10213&quot;&gt;&lt;strong&gt;Project Management Institute (PMI)&lt;/strong&gt; — &lt;em&gt;Blending Agile and Waterfall&lt;/em&gt;&lt;/a&gt;
Professional guidance on hybrid delivery models.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-17&quot;&gt;&lt;/a&gt;
[17] &lt;a href=&quot;https://www.pmi.org/learning/library/outcomes-hybrid-approach-waterfall-environment-5839&quot;&gt;&lt;strong&gt;Deloitte (via PMI case studies)&lt;/strong&gt; — &lt;em&gt;Hybrid Agile-Waterfall Delivery&lt;/em&gt;&lt;/a&gt;
Enterprise case studies showing hybrid process adoption.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-18&quot;&gt;&lt;/a&gt;
[18] &lt;a href=&quot;https://ieeexplore.ieee.org/document/9936036&quot;&gt;&lt;strong&gt;IEEE (2022)&lt;/strong&gt; — &lt;em&gt;The Waterfall Model with Agile Scrum as the Hybrid Agile Model&lt;/em&gt;&lt;/a&gt;
Peer-reviewed study supporting hybrid methodology adoption.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-19&quot;&gt;&lt;/a&gt;
[19] &lt;a href=&quot;https://sre.google/sre-book/table-of-contents/&quot;&gt;&lt;strong&gt;Google&lt;/strong&gt; — &lt;em&gt;Site Reliability Engineering&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Foundational material on the emergence of SRE as a scaling response.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-20&quot;&gt;&lt;/a&gt;
[20] &lt;a href=&quot;https://dora.dev/research/&quot;&gt;&lt;strong&gt;DORA / Google Cloud&lt;/strong&gt; — &lt;em&gt;DevOps Role &amp;amp; Maturity Research&lt;/em&gt;&lt;/a&gt;
Surveys documenting recurring organizational and role evolution patterns.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-21&quot;&gt;&lt;/a&gt;
[21] &lt;a href=&quot;https://medium.com/@ciro.rizzo/the-evolution-of-the-software-engineering-role-945dd572f672&quot;&gt;&lt;strong&gt;Ciro Rizzo&lt;/strong&gt; — &lt;em&gt;The Evolution of the Software Engineering Role&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Industry view on how engineering roles have expanded and recombined.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-22&quot;&gt;&lt;/a&gt;
[22] &lt;a href=&quot;https://ieeexplore.ieee.org/document/8963684&quot;&gt;&lt;strong&gt;Jovanović et al.&lt;/strong&gt; — &lt;em&gt;Agile Transition and Adoption Frameworks&lt;/em&gt;&lt;/a&gt;
Systematic mapping study of role and process changes during Agile adoption.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-23&quot;&gt;&lt;/a&gt;
[23] &lt;a href=&quot;https://waydev.co/devops-maturity-model/&quot;&gt;&lt;strong&gt;Waydev / ThoughtWorks&lt;/strong&gt; — &lt;em&gt;DevOps &amp;amp; Platform Team Maturity&lt;/em&gt;&lt;/a&gt;
Industry analysis of over-specialization and recomposition into platform teams.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-24&quot;&gt;&lt;/a&gt;
[24] &lt;a href=&quot;https://alexkondov.com/the-t-shaped-engineer/&quot;&gt;&lt;strong&gt;Alex Kondov&lt;/strong&gt; — &lt;em&gt;The T-Shaped Engineer&lt;/em&gt;&lt;/a&gt;
Perspective on the shift back toward generalist skill sets.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-25&quot;&gt;&lt;/a&gt;
[25] &lt;a href=&quot;https://en.wikipedia.org/wiki/T-shaped_skills&quot;&gt;&lt;strong&gt;Wikipedia&lt;/strong&gt; — &lt;em&gt;T-shaped Skills&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Documents evolving skill models in organizations.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-26&quot;&gt;&lt;/a&gt;
[26] &lt;a href=&quot;https://en.wikipedia.org/wiki/Technical_debt&quot;&gt;&lt;strong&gt;Wikipedia&lt;/strong&gt; — &lt;em&gt;Technical Debt&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Foundational overview of Ward Cunningham’s metaphor.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-27&quot;&gt;&lt;/a&gt;
[27] &lt;a href=&quot;https://arxiv.org/pdf/2502.16277&quot;&gt;&lt;strong&gt;Gupta et al. (2025)&lt;/strong&gt; — &lt;em&gt;Measuring the Impact of Technical Debt on Development Effort&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Empirical study quantifying technical debt impact.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-28&quot;&gt;&lt;/a&gt;
[28] &lt;a href=&quot;https://arxiv.org/pdf/2309.12434&quot;&gt;&lt;strong&gt;Klotins et al. (2023)&lt;/strong&gt; — &lt;em&gt;Exploration of Technical Debt in Start-ups&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Study showing higher debt accumulation in startups.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-29&quot;&gt;&lt;/a&gt;
[29] &lt;a href=&quot;https://doi.org/10.1016/j.infsof.2023.107216&quot;&gt;&lt;strong&gt;Runeson et al. (2023)&lt;/strong&gt; — &lt;em&gt;Lifecycle of Technical Debt&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Longitudinal analysis of debt accumulation and remediation.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-30&quot;&gt;&lt;/a&gt;
[30] &lt;a href=&quot;https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/&quot;&gt;&lt;strong&gt;Joel Spolsky (2000)&lt;/strong&gt; — &lt;em&gt;Things You Should Never Do, Part I&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Landmark essay on rewrite risks.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-31&quot;&gt;&lt;/a&gt;
[31] &lt;a href=&quot;https://morphis-tech.com/blog/rewrite-case-studies/&quot;&gt;&lt;strong&gt;Morphis Insights&lt;/strong&gt; — &lt;em&gt;Rewrite Code from Scratch?&lt;/em&gt;&lt;/a&gt;
Case studies of large-scale rewrite failures.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-32&quot;&gt;&lt;/a&gt;
[32] &lt;a href=&quot;https://medium.com/adobetech/we-decided-to-rewrite-our-software-you-wont-believe-what-happened-next-dd03574f6654&quot;&gt;&lt;strong&gt;Aaron Hardy (2019)&lt;/strong&gt; — &lt;em&gt;We Decided to Rewrite Our Software&lt;/em&gt;&lt;/a&gt;
Adobe’s successful rewrite case study.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-33&quot;&gt;&lt;/a&gt;
[33] &lt;a href=&quot;https://medium.com/@herbcaudill/lessons-from-6-software-rewrite-stories-635e4c8f7c22&quot;&gt;&lt;strong&gt;Herb Caudill (2019)&lt;/strong&gt; — &lt;em&gt;Lessons from 6 Software Rewrite Stories&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;
Comparative analysis of rewrite outcomes.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;ref-34&quot;&gt;&lt;/a&gt;
[34] &lt;a href=&quot;https://www.mckinsey.com/capabilities/tech-and-ai/our-insights/breaking-technical-debts-vicious-cycle-to-modernize-your-business&quot;&gt;&lt;strong&gt;McKinsey &amp;amp; Company&lt;/strong&gt; — &lt;em&gt;The Cost of Technical Debt&lt;/em&gt;&lt;/a&gt;
Estimates technical debt at 20–40% of total technology estate value.&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/01/12/software-house-evolution/</guid>
      </item>
    
      <item>
        <title>A Practical Git Branching Strategy for Multi-Version Product Organizations</title>
        <description>&lt;h2 id=&quot;why-git-branching-is-a-strategic-decision&quot;&gt;Why Git Branching Is a Strategic Decision&lt;/h2&gt;

&lt;p&gt;Managing Git branching in product organizations — especially in fintech and other regulated domains — is not a tooling choice. It is a &lt;strong&gt;systems-level decision&lt;/strong&gt; that directly influences delivery speed, stability, auditability, and engineering culture.&lt;/p&gt;

&lt;p&gt;As products mature, teams must support:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Multiple customers on different versions&lt;/li&gt;
  &lt;li&gt;Customer-specific behavior and regulatory requirements&lt;/li&gt;
  &lt;li&gt;Parallel product development and production support&lt;/li&gt;
  &lt;li&gt;Emergency fixes under strict SLAs&lt;/li&gt;
  &lt;li&gt;Long-term product evolution without fragmentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a fundamental challenge:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;How do you evolve a single product while supporting multiple customer realities — without breaking either?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post outlines a &lt;strong&gt;practical Git branching strategy&lt;/strong&gt; that addresses this challenge at an organizational level.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-core-problem-most-teams-face&quot;&gt;The Core Problem Most Teams Face&lt;/h2&gt;

&lt;p&gt;Most engineering teams start with good intentions but end up in one of these extremes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Over-simplified branching&lt;/strong&gt;&lt;br /&gt;
Works early, collapses under scale and multiple customers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Over-engineered branching&lt;/strong&gt;&lt;br /&gt;
Becomes slow, fragile, and intimidating for developers.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real challenge is balancing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Product-centric development&lt;/li&gt;
  &lt;li&gt;Customer-specific delivery needs&lt;/li&gt;
  &lt;li&gt;Long-term maintainability&lt;/li&gt;
  &lt;li&gt;Operational confidence during releases&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-systems-view-of-git-branching&quot;&gt;A Systems View of Git Branching&lt;/h2&gt;

&lt;p&gt;At a systems level, a Git repository is a &lt;strong&gt;control plane&lt;/strong&gt; for your product.&lt;/p&gt;

&lt;p&gt;Your branching strategy should clearly separate:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Product evolution&lt;/strong&gt; (where innovation happens)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Release stability&lt;/strong&gt; (what customers rely on)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Customer isolation&lt;/strong&gt; (who gets what, and when)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation reduces cognitive load, enables parallel workstreams, and makes failures &lt;em&gt;containable&lt;/em&gt; rather than &lt;em&gt;systemic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Think of branches as &lt;strong&gt;organizational boundaries&lt;/strong&gt;, not just technical ones.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;product-centric-first-customer-centric-second&quot;&gt;Product-Centric First, Customer-Centric Second&lt;/h2&gt;

&lt;p&gt;A key mindset shift is recognizing that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Products should be the primary axis — customers are consumers of product versions, not owners of codebases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many organizations maintain separate repositories per customer. While this feels customer-centric, it leads to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Duplication of effort&lt;/li&gt;
  &lt;li&gt;Diverging logic&lt;/li&gt;
  &lt;li&gt;Inconsistent security posture&lt;/li&gt;
  &lt;li&gt;Painful upgrades&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A product-centric branching model keeps &lt;strong&gt;one source of truth&lt;/strong&gt;, while still allowing controlled customer customization where absolutely necessary.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;scaling-without-chaos&quot;&gt;Scaling Without Chaos&lt;/h2&gt;

&lt;p&gt;As teams and customers grow, branching must support:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Parallel feature development&lt;/li&gt;
  &lt;li&gt;Controlled releases&lt;/li&gt;
  &lt;li&gt;Emergency fixes without disruption&lt;/li&gt;
  &lt;li&gt;Predictable promotion paths (development → release → production)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A scalable strategy minimizes long-lived divergence and makes merges &lt;strong&gt;intentional events&lt;/strong&gt;, not daily firefighting exercises.&lt;/p&gt;

&lt;p&gt;At scale, clarity beats cleverness.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;cultural-impact-why-developers-either-love-or-hate-git&quot;&gt;Cultural Impact: Why Developers Either Love or Hate Git&lt;/h2&gt;

&lt;p&gt;Branching strategies silently shape engineering culture.&lt;/p&gt;

&lt;p&gt;A good strategy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Makes the &lt;em&gt;right path obvious&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Reduces fear of breaking production&lt;/li&gt;
  &lt;li&gt;Encourages ownership and accountability&lt;/li&gt;
  &lt;li&gt;Supports junior and senior developers equally&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A bad one creates tribal knowledge, gatekeeping, and hesitation.&lt;/p&gt;

&lt;p&gt;Git should &lt;strong&gt;enable flow&lt;/strong&gt;, not demand heroics.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;governance-without-bureaucracy&quot;&gt;Governance Without Bureaucracy&lt;/h2&gt;

&lt;p&gt;In regulated industries like fintech, governance is unavoidable — but it does not need to be heavy-handed.&lt;/p&gt;

&lt;p&gt;A well-defined branching strategy enables:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Auditable change history&lt;/li&gt;
  &lt;li&gt;Clear release ownership&lt;/li&gt;
  &lt;li&gt;Controlled hotfix paths&lt;/li&gt;
  &lt;li&gt;Clean integration with CI/CD and approval workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Governance should emerge naturally from structure, not manual policing.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;where-this-strategy-fits-best&quot;&gt;Where This Strategy Fits Best&lt;/h2&gt;

&lt;p&gt;This approach works particularly well for organizations that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Build core fintech platforms or products&lt;/li&gt;
  &lt;li&gt;Serve multiple enterprise customers&lt;/li&gt;
  &lt;li&gt;Need controlled but frequent releases&lt;/li&gt;
  &lt;li&gt;Aim to mature from project-led to product-led delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;trunk-based-development-as-the-foundation&quot;&gt;Trunk-Based Development as the Foundation&lt;/h2&gt;

&lt;p&gt;At the center of this model is &lt;strong&gt;trunk-based development&lt;/strong&gt;.  &lt;img src=&quot;/assets/img/blog/git-branching/trunk-based-development.png&quot; alt=&quot;Trunk-based development&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;All product development flows through a single, continuously evolving branch:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The trunk represents the &lt;em&gt;future of the product&lt;/em&gt;. It is where features are integrated, tested, and prepared for release.&lt;/p&gt;

&lt;p&gt;Feature branches are intentionally short-lived and merged back into main frequently. This minimizes long-term divergence and keeps integration friction low.&lt;/p&gt;

&lt;p&gt;The trunk is &lt;strong&gt;not frozen for customers&lt;/strong&gt; — it exists to preserve momentum and clarity in product evolution.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;release-branches-separating-stability-from-innovation&quot;&gt;Release Branches: Separating Stability from Innovation&lt;/h2&gt;

&lt;p&gt;To support customers running different versions, the product lifecycle is anchored by &lt;strong&gt;release branches&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Release branches represent &lt;strong&gt;stable snapshots&lt;/strong&gt; of the product and are created intentionally when a version is ready for delivery.&lt;/p&gt;

&lt;p&gt;They serve to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Freeze scope&lt;/li&gt;
  &lt;li&gt;Stabilize quality&lt;/li&gt;
  &lt;li&gt;Support certification and compliance&lt;/li&gt;
  &lt;li&gt;Act as a base for customer deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once created, release branches accept only fixes — not new features. Product innovation continues on main without disrupting delivery timelines.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;customer-branches-controlled-customization-without-fragmentation&quot;&gt;Customer Branches: Controlled Customization Without Fragmentation&lt;/h2&gt;

&lt;p&gt;Enterprise customers often require:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Custom workflows&lt;/li&gt;
  &lt;li&gt;Regulatory adaptations&lt;/li&gt;
  &lt;li&gt;Integration-specific behavior&lt;/li&gt;
  &lt;li&gt;Temporary patches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Customer-specific changes must not leak into the core product by default.&lt;/p&gt;

&lt;p&gt;For this reason, customer delivery happens on &lt;strong&gt;customer branches&lt;/strong&gt;, derived from a specific release version.&lt;/p&gt;

&lt;p&gt;This approach ensures:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Product evolution remains clean&lt;/li&gt;
  &lt;li&gt;Customer requirements are isolated and explicit&lt;/li&gt;
  &lt;li&gt;Customizations are auditable and reversible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only changes with clear product value are later generalized and merged into main.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;scenario-based-views-how-the-strategy-behaves&quot;&gt;Scenario-Based Views (How the Strategy Behaves)&lt;/h2&gt;

&lt;p&gt;The following scenarios illustrate &lt;strong&gt;how this branching strategy behaves in real-world situations&lt;/strong&gt;. These are conceptual flows, not procedural steps.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;scenario-1-standard-product-development-and-release&quot;&gt;Scenario 1: Standard Product Development and Release&lt;/h3&gt;

&lt;p&gt;This scenario shows how new product features flow from development into a stable release.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/git-branching/scenario-product-release.png&quot; alt=&quot;Scenario 1: Product Development to Release&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this illustrates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Feature work merges into main&lt;/li&gt;
  &lt;li&gt;Main continues to evolve independently&lt;/li&gt;
  &lt;li&gt;A release branch is cut at a defined stabilization point&lt;/li&gt;
  &lt;li&gt;Customers receive stable, versioned releases&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;scenario-2-customer-specific-customization&quot;&gt;Scenario 2: Customer-Specific Customization&lt;/h3&gt;

&lt;p&gt;This scenario demonstrates how customer-specific behavior is isolated without affecting the product roadmap.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/git-branching/scenario-customer-branch.png&quot; alt=&quot;Scenario 2: Customer-Specific Branching&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this illustrates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Customer branches are created from a release&lt;/li&gt;
  &lt;li&gt;Custom behavior remains isolated&lt;/li&gt;
  &lt;li&gt;The core product remains unaffected&lt;/li&gt;
  &lt;li&gt;Product evolution continues independently&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;scenario-3-product-bug-fix-propagation&quot;&gt;Scenario 3: Product Bug Fix Propagation&lt;/h3&gt;

&lt;p&gt;This scenario shows how a product fix is applied and propagated across versions.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/git-branching/scenario-fix-propagation.png&quot; alt=&quot;Scenario 3: Product Fix Propagation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this illustrates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fixes are applied to the product first&lt;/li&gt;
  &lt;li&gt;Stability improvements flow forward&lt;/li&gt;
  &lt;li&gt;Customers inherit fixes without manual rework&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;scenario-4-customer-upgrade-to-a-new-product-version&quot;&gt;Scenario 4: Customer Upgrade to a New Product Version&lt;/h3&gt;

&lt;p&gt;This scenario demonstrates a clean and controlled customer upgrade.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/blog/git-branching/scenario-customer-upgrade.png&quot; alt=&quot;Scenario 4: Customer Upgrade Strategy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this illustrates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Upgrades start from a clean new release&lt;/li&gt;
  &lt;li&gt;Only required customer-specific changes are reapplied&lt;/li&gt;
  &lt;li&gt;Historical complexity is intentionally discarded&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;exceptional-scenarios-handling-reality-without-breaking-the-system&quot;&gt;Exceptional Scenarios: Handling Reality Without Breaking the System&lt;/h2&gt;

&lt;p&gt;No branching strategy operates in a perfectly controlled environment.&lt;br /&gt;
In long-lived product organizations, especially in fintech, &lt;strong&gt;exceptions are part of business-as-usual (BAU)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal is not to eliminate exceptions, but to ensure they &lt;strong&gt;do not clutter the product, distort the roadmap, or fragment the codebase&lt;/strong&gt; over time.&lt;/p&gt;

&lt;p&gt;Exceptional scenarios fall into two broad categories:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;BAU-driven operational exceptions&lt;/li&gt;
  &lt;li&gt;Product-level decisions required to safeguard long-term scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;bau-exceptions-operational-reality-at-scale&quot;&gt;BAU Exceptions: Operational Reality at Scale&lt;/h2&gt;

&lt;p&gt;These scenarios arise from day-to-day production support and customer operations.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;emergency-fixes-that-are-also-product-relevant&quot;&gt;Emergency Fixes That Are Also Product-Relevant&lt;/h3&gt;

&lt;p&gt;There are cases where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A customer faces a production issue requiring immediate resolution&lt;/li&gt;
  &lt;li&gt;The root cause exists in core product logic&lt;/li&gt;
  &lt;li&gt;The fix is relevant beyond a single customer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In such situations, the fix must be treated as a &lt;strong&gt;product fix&lt;/strong&gt;, not a customer patch.&lt;/p&gt;

&lt;p&gt;The guiding principles are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The fix ultimately belongs to the product&lt;/li&gt;
  &lt;li&gt;Customer urgency does not override product integrity&lt;/li&gt;
  &lt;li&gt;Temporary isolation may be necessary, but permanent divergence is not&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Emergency paths must always converge back into the product flow to avoid silent forks.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;product-fixes-that-break-customer-specific-features&quot;&gt;Product Fixes That Break Customer-Specific Features&lt;/h3&gt;

&lt;p&gt;Product fixes, when rolled out to customers, can occasionally break:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Customer-specific workflows&lt;/li&gt;
  &lt;li&gt;Custom integrations&lt;/li&gt;
  &lt;li&gt;Regulatory adaptations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not invalidate the product fix.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The product fix remains intact&lt;/li&gt;
  &lt;li&gt;Customer branches are adjusted to restore compatibility&lt;/li&gt;
  &lt;li&gt;The product is not reshaped to preserve isolated customer behavior by default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This preserves forward momentum while respecting customer commitments.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;product-fixes-that-are-not-relevant-for-certain-customers&quot;&gt;Product Fixes That Are Not Relevant for Certain Customers&lt;/h3&gt;

&lt;p&gt;Some customers may continue operating on very old product versions due to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compliance certification cycles&lt;/li&gt;
  &lt;li&gt;Contractual or operational constraints&lt;/li&gt;
  &lt;li&gt;Risk tolerance within their organizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In such cases:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Not every product fix is automatically applicable&lt;/li&gt;
  &lt;li&gt;Fixes are evaluated for relevance and feasibility&lt;/li&gt;
  &lt;li&gt;If a fix can be safely adjusted, it may be backported&lt;/li&gt;
  &lt;li&gt;Otherwise, the limitation is documented and accepted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids the illusion that all versions must evolve equally.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;product-safeguard-exceptions-protecting-long-term-clarity&quot;&gt;Product Safeguard Exceptions: Protecting Long-Term Clarity&lt;/h2&gt;

&lt;p&gt;These scenarios are less about immediate operations and more about &lt;strong&gt;preventing long-term product clutter&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;new-product-features-not-supported-on-older-versions&quot;&gt;New Product Features Not Supported on Older Versions&lt;/h3&gt;

&lt;p&gt;As products evolve, new features may depend on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Architectural changes&lt;/li&gt;
  &lt;li&gt;Data model evolution&lt;/li&gt;
  &lt;li&gt;Platform capabilities not present in older releases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supporting every historical version indefinitely is neither realistic nor healthy.&lt;/p&gt;

&lt;p&gt;A clear support policy is required, for example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Only the latest version and the previous two versions (N-2) are supported&lt;/li&gt;
  &lt;li&gt;Customers on older versions must upgrade to access new functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a sustainable balance between customer flexibility and product evolution.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;customer-features-promoted-to-product-features&quot;&gt;Customer Features Promoted to Product Features&lt;/h3&gt;

&lt;p&gt;Some customer-specific features prove to be broadly valuable.&lt;/p&gt;

&lt;p&gt;When this happens:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The feature is reassessed from a product perspective&lt;/li&gt;
  &lt;li&gt;Assumptions tied to a single customer are removed&lt;/li&gt;
  &lt;li&gt;The feature is generalized, hardened, and documented&lt;/li&gt;
  &lt;li&gt;It is then introduced into the product through normal product development flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This transforms customer-driven innovation into &lt;strong&gt;intentional product value&lt;/strong&gt;, rather than accidental complexity.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-discipline-behind-exceptional-scenarios&quot;&gt;The Discipline Behind Exceptional Scenarios&lt;/h2&gt;

&lt;p&gt;Exceptional scenarios should follow one unifying rule:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Exceptions may solve immediate problems, but they must not redefine the system.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Healthy systems ensure that exceptions are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Explicit&lt;/li&gt;
  &lt;li&gt;Intentional&lt;/li&gt;
  &lt;li&gt;Time-bound&lt;/li&gt;
  &lt;li&gt;Reconciled with the product roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When exceptions become frequent, informal, or permanent, the branching strategy is no longer scaling — it is eroding.&lt;/p&gt;

&lt;p&gt;Strong product organizations absorb operational pressure &lt;strong&gt;without changing their shape&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;organizational-outcomes-of-this-strategy&quot;&gt;Organizational Outcomes of This Strategy&lt;/h2&gt;

&lt;p&gt;Branching strategies silently shape engineering culture.&lt;/p&gt;

&lt;p&gt;A well-designed model:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Makes the right path obvious&lt;/li&gt;
  &lt;li&gt;Reduces fear of breaking production&lt;/li&gt;
  &lt;li&gt;Encourages ownership and accountability&lt;/li&gt;
  &lt;li&gt;Supports predictable delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Poor branching models create hesitation, tribal knowledge, and dependency on a few senior engineers.&lt;/p&gt;

&lt;p&gt;Git should &lt;strong&gt;enable flow&lt;/strong&gt;, not demand heroics.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;

&lt;p&gt;This Git branching strategy is not about complexity — it is about &lt;strong&gt;clarity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It enables organizations to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Scale product development&lt;/li&gt;
  &lt;li&gt;Support diverse customer needs&lt;/li&gt;
  &lt;li&gt;Maintain delivery confidence&lt;/li&gt;
  &lt;li&gt;Protect long-term product evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a follow-up post, I’ll focus on &lt;strong&gt;practical implementation&lt;/strong&gt;, including branch naming, workflow rules, and CI/CD alignment.&lt;/p&gt;

&lt;hr /&gt;

</description>
        <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2026/01/02/practical-git-branching-fintech/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2026/01/02/practical-git-branching-fintech/</guid>
      </item>
    
      <item>
        <title>TECTONICS: Systems, Culture &amp; Scale</title>
        <description>&lt;p&gt;This space is a record of how technology organizations actually move.&lt;/p&gt;

&lt;p&gt;TECTONICS explores the &lt;strong&gt;systems&lt;/strong&gt;, &lt;strong&gt;culture&lt;/strong&gt;, and &lt;strong&gt;scale dynamics&lt;/strong&gt; that shape outcomes — from architecture and platforms to leadership decisions and organizational trade-offs.&lt;/p&gt;

&lt;p&gt;This is not a tutorial blog.&lt;br /&gt;
It is a reflection on what works, what fails, and why.&lt;/p&gt;
</description>
        <pubDate>Fri, 26 Dec 2025 00:00:00 +0000</pubDate>
        <link>https://aathawerani.github.io/systems/culture/scale/2025/12/26/tectonics-introduction/</link>
        <guid isPermaLink="true">https://aathawerani.github.io/systems/culture/scale/2025/12/26/tectonics-introduction/</guid>
      </item>
    

    
      
        
      
    
      
    
      
    
      
        
          <item>
            <title></title>
            <description>&lt;h3&gt;   &lt;/h3&gt;

&lt;div id=&quot;categories&quot;&gt;

  &lt;div class=&quot;category-box&quot;&gt;
    
    &lt;div id=&quot;#systems&quot;&gt;&lt;/div&gt;
    &lt;h4 class=&quot;category-head&quot;&gt;&lt;a href=&quot;/blog/categories/systems&quot;&gt;systems&lt;/a&gt;&lt;/h4&gt;
    &lt;a name=&quot;systems&quot;&gt;&lt;/a&gt;
     
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/&quot;&gt;A Requirement Rather Than a Reality&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;The Hollow Sprint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/08/02/the-evaluation-constraint/&quot;&gt;The Evaluation Constraint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/&quot;&gt;The CTO Decision Stack in Startup and Enterprise&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;AI Across the CTO Decision Stack&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;The CTO Decision Stack&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;Tech Stack Selection in the Age of AI Agents&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/16/FYP-to-market/&quot;&gt;From Project to Product to Company — What the Transition Actually Requires&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/02/pipeline-not-the-problem/&quot;&gt;The Pipeline Is Not the Problem&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling: What AI Is Doing to Software Architecture — and Why the Rewrite Is No Longer the Last Resort&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/03/15/Designing-for-scale/&quot;&gt;Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles: Why Software Houses Keep Returning to Square One&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/02/practical-git-branching-fintech/&quot;&gt;A Practical Git Branching Strategy for Multi-Version Product Organizations&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2025/12/26/tectonics-introduction/&quot;&gt;TECTONICS: Systems, Culture &amp;amp; Scale&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    

  &lt;/div&gt;

  &lt;div class=&quot;category-box&quot;&gt;
    
    &lt;div id=&quot;#culture&quot;&gt;&lt;/div&gt;
    &lt;h4 class=&quot;category-head&quot;&gt;&lt;a href=&quot;/blog/categories/culture&quot;&gt;culture&lt;/a&gt;&lt;/h4&gt;
    &lt;a name=&quot;culture&quot;&gt;&lt;/a&gt;
     
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/&quot;&gt;A Requirement Rather Than a Reality&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;The Hollow Sprint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/08/02/the-evaluation-constraint/&quot;&gt;The Evaluation Constraint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/&quot;&gt;The CTO Decision Stack in Startup and Enterprise&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot;&gt;AI Across the CTO Decision Stack&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/2026/06/07/cto-decision-stack/&quot;&gt;The CTO Decision Stack&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/16/FYP-to-market/&quot;&gt;From Project to Product to Company — What the Transition Actually Requires&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/02/pipeline-not-the-problem/&quot;&gt;The Pipeline Is Not the Problem&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/03/15/Designing-for-scale/&quot;&gt;Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles: Why Software Houses Keep Returning to Square One&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/02/practical-git-branching-fintech/&quot;&gt;A Practical Git Branching Strategy for Multi-Version Product Organizations&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2025/12/26/tectonics-introduction/&quot;&gt;TECTONICS: Systems, Culture &amp;amp; Scale&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    

  &lt;/div&gt;

  &lt;div class=&quot;category-box&quot;&gt;
    
    &lt;div id=&quot;#scale&quot;&gt;&lt;/div&gt;
    &lt;h4 class=&quot;category-head&quot;&gt;&lt;a href=&quot;/blog/categories/scale&quot;&gt;scale&lt;/a&gt;&lt;/h4&gt;
    &lt;a name=&quot;scale&quot;&gt;&lt;/a&gt;
     
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/&quot;&gt;A Requirement Rather Than a Reality&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot;&gt;The Hollow Sprint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/08/02/the-evaluation-constraint/&quot;&gt;The Evaluation Constraint&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/&quot;&gt;The CTO Decision Stack in Startup and Enterprise&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/scale/2026/05/27/tech-stack-ai-agents/&quot;&gt;Tech Stack Selection in the Age of AI Agents&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/16/FYP-to-market/&quot;&gt;From Project to Product to Company — What the Transition Actually Requires&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/05/02/pipeline-not-the-problem/&quot;&gt;The Pipeline Is Not the Problem&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/scale/2026/03/23/cognitive-load-ceiling/&quot;&gt;The Cognitive Load Ceiling: What AI Is Doing to Software Architecture — and Why the Rewrite Is No Longer the Last Resort&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/03/15/Designing-for-scale/&quot;&gt;Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/12/software-house-evolution/&quot;&gt;The Inevitable Cycles: Why Software Houses Keep Returning to Square One&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2026/01/02/practical-git-branching-fintech/&quot;&gt;A Practical Git Branching Strategy for Multi-Version Product Organizations&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/culture/scale/2025/12/26/tectonics-introduction/&quot;&gt;TECTONICS: Systems, Culture &amp;amp; Scale&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    

  &lt;/div&gt;

  &lt;div class=&quot;category-box&quot;&gt;
    
    &lt;div id=&quot;#architecture&quot;&gt;&lt;/div&gt;
    &lt;h4 class=&quot;category-head&quot;&gt;&lt;a href=&quot;/blog/categories/architecture&quot;&gt;architecture&lt;/a&gt;&lt;/h4&gt;
    &lt;a name=&quot;architecture&quot;&gt;&lt;/a&gt;
     
    &lt;article class=&quot;center&quot;&gt;
      &lt;h6&gt;&lt;a href=&quot;/systems/architecture/scale/2026/05/09/rewrite-preconditions/&quot;&gt;Why Architecture Is Shifting From Diagrams to Guardrails&lt;/a&gt;&lt;/h6&gt;
    &lt;/article&gt;


    

  &lt;/div&gt;

&lt;/div&gt;

</description>
            <link>https://aathawerani.github.io/blog/categories/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Blog</title>
            <description>&lt;h2 id=&quot;tectonics&quot;&gt;TECTONICS&lt;/h2&gt;
&lt;h3 id=&quot;systems-culture--scale&quot;&gt;Systems, Culture &amp;amp; Scale&lt;/h3&gt;

</description>
            <link>https://aathawerani.github.io/blog/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Culture</title>
            <description>
&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/requirement-not-reality/requirement-not-reality-thumbnail.svg&quot; alt=&quot;A Requirement Rather Than a Reality&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;A Requirement Rather Than a Reality&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Oct 29, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Software engineering was named in 1968 as an aspiration, not a description: a discipline the field decided it needed because too much was falling through the cracks. Vibe coding is interesting not because it uses AI, but because it can separate producing code from the human responsibility to understand it, a responsibility that review, testing, traceability and change control all depend on. How much discipline a system needs depends on how long it lives and what it touches. Fintech products sit at the far end of both, and there the discipline is written into the standards. Vibe coding still has a place, at the start, as a way of seeing requirements, but the prototype is not a signed baseline: what is worth freezing is the load-bearing decisions, not every screen. Spec-driven development can hold those decisions, but only if the spec keeps being maintained; a tool is not the discipline itself.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/10/29/a-requirement-rather-than-a-reality/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/hollow-sprint/hollow-sprint-thumbnail.svg&quot; alt=&quot;The Hollow Sprint&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The Hollow Sprint&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Oct 9, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Agile was an answer to uncertainty at a time when building software was expensive: plan little, build small, learn from what the customer sees. AI has made build capacity and decision capacity diverge. A team that keeps its old rhythm ends up running hollow sprints: on schedule, every ceremony intact, with more and more unconfirmed decisions inside them. Cheaper building could justify more upfront planning or even more iteration, and both are right, for different kinds of decision. AI moves the last responsible moment in two directions at once. The unit of methodology is no longer the project. It is the decision.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/10/09/the-hollow-sprint/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/evaluation-constraint/evaluation-constraint-thumbnail.svg&quot; alt=&quot;The Evaluation Constraint&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The Evaluation Constraint&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Aug 2, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Two engineering organizations with the same headcount, the same budget and the same stack will diverge enormously over five years, and the divergence is not talent or effort. It is which allocation of capacity they found. Superior allocations exist, they are rare, and finding one is a search problem — which means the arm of that search AI just made cheap is not the arm that was ever binding.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/08/02/the-evaluation-constraint/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/startup-enterprise-cto-decision-stack/startup-enterprise-cto-decision-stack-thumbnail.svg&quot; alt=&quot;The CTO Decision Stack in Startup and Enterprise&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The CTO Decision Stack in Startup and Enterprise&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Jul 12, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      The third post in the CTO Decision Stack series. The seven layers don&apos;t change between a ten-person startup and a ten-thousand-person enterprise. What changes is what each layer is optimizing for, given different constraints — capital, reputational exposure, existing assets, and time horizon. A startup shipping a throwaway product to win a deal and an enterprise refusing to is not one of them being undisciplined. Both can be right. The recurring failure isn&apos;t a bad decision at either end. It&apos;s importing a tradeoff that was correct somewhere else.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/07/12/startup-enterprise-cto-decision-stack/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/ai-across-cto-decision-stack/ai-across-cto-decision-stack-thumbnail.png&quot; alt=&quot;AI Across the CTO Decision Stack&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;AI Across the CTO Decision Stack&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Jun 14, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      AI is not a layer-seven tool — it&apos;s a force that changes the cost structure, failure modes, and governance requirements of all seven layers of the CTO Decision Stack at once. This post walks the stack layer by layer, tracing how a single tooling adoption decision leaves six other layers with open questions nobody asked.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/2026/06/14/ai-across-cto-decision-stack/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/cto-decision-stack/cto-decision-stack-thumbnail.svg&quot; alt=&quot;The CTO Decision Stack&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The CTO Decision Stack&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Jun 7, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Most technical leadership failures are not failures of the wrong decision. They are failures of the wrong layer — the right question answered at the wrong altitude, by the wrong people, against the wrong criteria. The CTO Decision Stack maps seven distinct layers of decision-making, from corporate strategy to developer productivity, and shows why conflating them is how organizations accumulate consequences they cannot trace back to a cause.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/2026/06/07/cto-decision-stack/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/fyp-to-market/fyp_to_market_thumbnail.svg&quot; alt=&quot;From Project to Product to Company — What the Transition Actually Requires&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;From Project to Product to Company — What the Transition Actually Requires&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      May 16, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Most final year projects successfully prove something can be built. The harder questions — will someone use this repeatedly, and can it survive when conditions change — are what the next step requires. This post maps the transition from project to product to company: what it takes to find the hidden need, build the feedback loop, understand the landscape, and bring something real to the world.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/05/16/FYP-to-market/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/pipeline-not-problem/pipeline-not-problem-thumbnail.png&quot; alt=&quot;The Pipeline Is Not the Problem&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The Pipeline Is Not the Problem&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      May 2, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      Most SDLC policies don’t fail because they are poorly designed. They fail because they assume the system will sustain itself. Pipelines stay green, audits pass, and metrics look healthy — while the underlying system quietly degrades. The problem isn’t the pipeline. It’s the gap between what the process enforces and what the culture rewards.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/05/02/pipeline-not-the-problem/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/designing-for-scale/designing-for-scale-thumbnail.png&quot; alt=&quot;Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;Designing for Scale Before Scaling: A Practical Reading of Conway&apos;s Law&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Mar 15, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      A structural perspective on scaling fintech systems using Conway&apos;s Law. Exploring how organizational structure, branching strategy, and delivery mechanics must align before growth introduces irreversible complexity.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/03/15/Designing-for-scale/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/software-evolution/software-house-evolution-thumbnail.png&quot; alt=&quot;The Inevitable Cycles: Why Software Houses Keep Returning to Square One&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;The Inevitable Cycles: Why Software Houses Keep Returning to Square One&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Jan 12, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      There and Back Again — from Cloud to On-Prem, Projects to Products. An exploration of why software houses repeatedly cycle through infrastructure, delivery models, processes, roles, and technical debt as they scale.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/01/12/software-house-evolution/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  
    &lt;img class=&quot;card-img-top&quot; src=&quot;https://aathawerani.github.io/assets/img/blog/git-branching/cover.png&quot; alt=&quot;A Practical Git Branching Strategy for Multi-Version Product Organizations&quot; /&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;A Practical Git Branching Strategy for Multi-Version Product Organizations&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Jan 2, 2026
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      A product-centric Git branching strategy that supports multiple customer versions, controlled customization, and scalable delivery without sacrificing engineering velocity.
    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2026/01/02/practical-git-branching-fintech/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;card blog-post&quot;&gt;
  

  &lt;div class=&quot;card-body center&quot;&gt;
    &lt;h4 class=&quot;card-title&quot;&gt;TECTONICS: Systems, Culture &amp;amp; Scale&lt;/h4&gt;

    &lt;h6 class=&quot;card-subtitle mb-2 text-muted&quot;&gt;
      Dec 26, 2025
    &lt;/h6&gt;

    &lt;p class=&quot;card-text&quot;&gt;
      &lt;p&gt;This space is a record of how technology organizations actually move.&lt;/p&gt;


    &lt;/p&gt;

    &lt;a href=&quot;/systems/culture/scale/2025/12/26/tectonics-introduction/&quot; class=&quot;btn btn-dark btn-lg&quot;&gt;
      Read
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

</description>
            <link>https://aathawerani.github.io/blog/categories/culture/</link>
          </item>
        
      
    
      
    
      
        
          <item>
            <title>Guides</title>
            <description>&lt;h5&gt; Posts by Category : {{ page.title }} &lt;/h5&gt;

&lt;div class=&quot;card&quot;&gt;
{% for post in site.categories.guides %}
 &lt;li class=&quot;category-posts&quot;&gt;&lt;span&gt;{{ post.date | date_to_string }}&lt;/span&gt; &amp;nbsp; &lt;a href=&quot;{{ post.url }}&quot;&gt;{{ post.title }}&lt;/a&gt;&lt;/li&gt;
{% endfor %}
&lt;/div&gt;</description>
            <link>https://aathawerani.github.io/blog/categories/guides/</link>
          </item>
        
      
    
      
    
      
    
      
        
          <item>
            <title>Jekyll</title>
            <description>&lt;h5&gt; Posts by Category : {{ page.title }} &lt;/h5&gt;

&lt;div class=&quot;card&quot;&gt;
{% for post in site.categories.jekyll %}
 &lt;li class=&quot;category-posts&quot;&gt;&lt;span&gt;{{ post.date | date_to_string }}&lt;/span&gt; &amp;nbsp; &lt;a href=&quot;{{ post.url }}&quot;&gt;{{ post.title }}&lt;/a&gt;&lt;/li&gt;
{% endfor %}
&lt;/div&gt;</description>
            <link>https://aathawerani.github.io/blog/categories/jekyll/</link>
          </item>
        
      
    
      
    
      
        
          <item>
            <title>Guides</title>
            <description>&lt;h5&gt; Posts by Category : {{ page.title }} &lt;/h5&gt;

&lt;div class=&quot;card&quot;&gt;
{% for post in site.categories.sample_category %}
 &lt;li class=&quot;category-posts&quot;&gt;&lt;span&gt;{{ post.date | date_to_string }}&lt;/span&gt; &amp;nbsp; &lt;a href=&quot;{{ post.url }}&quot;&gt;{{ post.title }}&lt;/a&gt;&lt;/li&gt;
{% endfor %}
&lt;/div&gt;</description>
            <link>https://aathawerani.github.io/blog/categories/sample_category/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Scale</title>
            <description>{% for post in site.categories.scale %}
  {% include blog_card.html %}
{% endfor %}
</description>
            <link>https://aathawerani.github.io/blog/categories/scale/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Systems</title>
            <description>{% for post in site.categories.systems %}
  {% include blog_card.html %}
{% endfor %}
</description>
            <link>https://aathawerani.github.io/blog/categories/systems/</link>
          </item>
        
      
    
      
    
      
        
          <item>
            <title>Change Log</title>
            <description># Change Log

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

**Note that references to the Font-Awesome-Pro repository refer to a GitHub
repository that is by invitation only. You will get a 404 - Not Found if you do
not have access**

---

## [5.1.0](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.1.0)  - 2018-06-20

**Minor version upgrade notice: there are some backward-incompatible changes to this release. See the
[UPGRADING.md guide](https://github.com/FortAwesome/Font-Awesome/blob/master/UPGRADING.md) for more
information.**

### Added
* New Emoji, Design, and Travel category pack
* Another group of requested and commissioned icons
* Version 4 shim for Web Fonts with CSS
* New simplified download and NPM packages
* @fortawesome/fontawesome-free and @fortawesome/fontawesome-pro NPM packages that match what&apos;s available in the CDN and .ZIP files
* Brand icons rev, nimblr, megaport, mailchimp, hornbill, wix, weebly, themeco, squarespace, aws, shopware
* API method toHtml() for converting abstract objects to HTML
* API method counter() to generate Layers Counters
* API method watch() to configure MutationObserver and watch DOM for icon changes and additions

### Changed
* Relocating sponsor data to a separate sponsors.yml
* Updated teamspeak brand icon
* No more default exports in the CommonJS/ES packages (anything installed from NPM)
* Greatly improved performance and rendering of CSS pseudo-elements with SVG and JavaScript
* Configuration of SVG with JavaScript can now be done with attributes on the script tag
* SVG with JavaScript pseudo-elements now match syntax (font-family, font-weight) of Web Fonts with CSS

### Fixed
* Tree shaking of all NPM packages by default
* Alignment of the book-open and dice-six icon
* Correcting creative-commons
* Incorrect license on the fontawesome-common-types package
* Improve ligatures that share a base name with another ligature
* Correcting solid style of the digital-tachograph icon
* Prevent duplicating classes in some scenarios with SVG with JavaScript
* Duplicate insertion of CSS when insertCss() method was called
* Missing TypeScript definitions for the free-brands-svg-icons package

---

## [5.0.13](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.13)  - 2018-05-10

### Added
* 68 icons to Free and 165 to Pro of the most requested icons in Font Awesome

---

## [5.0.12](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.12)  - 2018-05-03

### Added
* A long time ago in a galaxy far, far away some icons were added

### Fixed
* Renamed the r brand to r-project to prevent ligature collision with the &quot;r&quot; glyph

---

## [5.0.11](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.11)  - 2018-05-01

### Added
* 16 new user icons
* Full set of Creative Commons symbols
* Regular style comment-dots used for v4 comment-alt in shim
* Top 6 brand icons: r, ebay, mastodon, researchgate, keybase, teamspeak

### Changed
* Revised slider icons FortAwesome/Font-Awesome#11872
* Make desktop typeface easier to find in apps that support ligature previews

### Fixed
* Remove errant XML entity from the lastfm-square icon FortAwesome/Font-Awesome#12847
* Correcting paths in cloud icons FortAwesome/Font-Awesome-Pro#920

---

## [5.0.10](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.10)  - 2018-04-10

### Added
* New java brand icon FortAwesome/Font-Awesome#386

### Changed
* Updating depth of dna icon
* Updating pied-piper, adding pied-piper-hat

### Fixed
* Correcting path errors on readme icon FortAwesome/Font-Awesome#12754
* Light style of lamp icon FortAwesome/Font-Awesome#12725

---

## [5.0.9](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.9)  - 2018-03-27

### Added
* New Chat icon pack and category
* New Charity icon pack and category
* New Moving icon pack and category
* New icons hands and hand-holding

### Changed
* Updated flipboard, readme, and houzz brand icon
* Making all solid icons in the medical icon pack free
* Updated hand-holding-box and hand-receiving in the Light style

### Fixed
* Missing box-sizing CSS property for fa-layers-counter

---

## [5.0.8](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.8)  - 2018-03-01

### Fixed
* OTF font files missing ligatures for Pro styles FortAwesome/Font-Awesome#12486 FortAwesome/Font-Awesome-Pro#1034

---

## [5.0.7](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.7)  - 2018-02-26

### Added
* New Logistics category
* New Medical category
* Individual SVG files available from the Font Awesome CDN
* Additional search terms

### Changed
* Apple brand icon update FortAwesome/Font-Awesome#12337
* Disable mutation observers with fontawesome.noAuto() is called
* License information now references https URL scheme

### Fixed
* Missing TypeScript names FortAwesome/react-fontawesome#83
* Adding categories metadata FortAwesome/Font-Awesome#12034
* TypeScript improvement for fontawesome.layer()
* Correcting a melting, wobbling, weird-looking whistle

---

## [5.0.6](https://github.com/FortAwesome/Font-Awesome/releases/tag/5.0.6)  - 2018-01-25

### Fixed
* @fortawesome/fontawesome-pro-light missing submodules

---

## [5.0.5](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.5)  - 2018-01-25

### Added
* New Sports category
* New Chess category
* Added brand icons for flipboard, php, quinscape, and hips

### Fixed
* Sass and Less mixin fa-icon() now uses ems instead of percentage
* Corrected misspelling of &quot;Alternate&quot; in category labels
* Improved TypeScript definitions for @fortawesome/fontawesome
* Server-side rendering was failing due to DOM-specific object access
* SVG attributes &quot;data-fa-processed&quot; renamed to &quot;data-fa-i2svg&quot;, only applies if rendered with i2svg() method

---

## [5.0.4](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.4)  - 2018-01-10

### Changed
* Updating all NPM package READMEs

### Fixed
* Improving TypeScript exports and fixing some incorrect definitions
* TypeScript error when importing entire style Fort-Awesome/Font-Awesome#12072
* Pseudo-elements erasing text contents in parent container Fort-Awesome/Font-Awesome-Pro#11995
* fa-layers-text misalignment when using Bootstrap Fort-Awesome/Font-Awesome#11871

---

## [5.0.3](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.3)  - 2018-01-08

### Added
* Adding elementor, youtube-square brand icons
* Adding window-minimize to the Free subset
* TypeScript support for all NPM packages

### Fixed
* Corrected uneven spacing in university, address-book, address-card, id-badge, id-card, mouse-pointer, phone-volume, portrait, user-alt, user-circle, user-md, user-plus, user-times, user , users
* Corrected uneven spacing in brand icons behance-square, dashcube, discourse, ember, erlang, fort-awesome, js-square, laravel, mix, patreon, palfed, phoenix-framework, node-js, skyatlas, stack-exchange, stripe, viber, weixin, yahoo , yoast

---

## [5.0.2](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.2)  - 2017-12-19

### Added
* Adding amazon-pay, cc-amazon-pay, korvue, ethereum brand icons
* Adding stopwatch to Free version

### Changed
* Ligatures now support capital case, all caps, and title case

### Fixed
* NPM packages now behave the same way as CDN and browser-specific packages FortAwesome/Font-Awesome-Pro#727 FortAwesome/Font-Awesome-Pro#896 FortAwesome/Font-Awesome-Pro#891
* Icon doesn&apos;t change when pseudo-element content changes FortAwesome/Font-Awesome-Pro#839
* Invalid XML in sprites FortAwesome/Font-Awesome-Pro#927
* Incorrect version in Sass and Less variable files

---

## [5.0.1](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.1)  - 2017-12-08

### Added
* Adding font-awesome-flag, lock-open, redo-alt, sync-alt, undo-alt to the Free version
* New NPM packages `fontawesome-free-webfonts` and `fontawesome-pro-webfonts`
* Adding old icon names to search terms for renamed icons
* Extensive metadata added to the `advanced-options` directory
* Adding stripe-s brand icon
* Adding typo3 brand icon

### Changed
* Updated dropbox brand icon to match new branding guidelines
* Updated firefox brand icon
* Updated strava brand icon
* OTF font file now include a space character

### Fixed
* OTF font file now supports different styles in Windows
* OTF font file &quot;j&quot; character now has correct space on the right
* Modifying the `class` attribute on an existing `&lt;svg&gt;` allows you to change the icon

---

## [5.0.0](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0)  - 2017-12-01

### Added
* License information

### Changed
* CSS vertical-align now &quot;em&quot;-based instead of percentage making it more consistent
* fa-ul width now closer to default browser size

---

## [5.0.0-rc5](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-rc5)  - 2017-11-28

**This release includes breaking changes**

### Added
* Brand icons: gitter, cc-stripe, stripe, hooli, aviato, strava, ember, angular, font-awesome-flag
* Icons compress-alt and expand-alt
* Adding calendar to Font Awesome 5 Free
* SASS function that makes it easier to use variables FortAwesome/Font-Awesome-Pro#824

### Changed
* BREAKING Renamed icon composition to mask (&quot;data-fa-compose&quot; becomes &quot;data-fa-mask&quot;)
* BREAKING Re-organized directory structure to match upcoming documentation
* BREAKING Font Awesome styles inserted into the `&lt;head&gt;` will now precede other link and style definitions
* BREAKING `fontawesome.text` and `fontawesome.icon` now use `styles` param instead of `style`
* Updated sizing for twitter, discord, youtube
* Class fa-li now respects line-height and has new recommended markup (see included docs)

### Fixed
* Duplicate `style` tags being added in the head FortAwesome/Font-Awesome-Pro#858
* Error with icon composition/masking that caused a confusing error message
* An error when using pseudo elements and the element is empty (Array.reduce error)
* Icons not being replaced with SVG if the text content is not empty

---

## [5.0.0-rc4](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-rc4)  - 2017-10-27

### Added
* Ligature support in the OTF font
* Vue.js brand icon
* Sass and Less brand icons
* Autoprefixer brand icon
* Individual icon imports in icon packages FortAwesome/Font-Awesome-Pro#808

### Changed
* Better poo eyes
* Renamed HTML status classes to `fontawesome-i2svg-active`, `fontawesome-i2svg-pending`, `fontawesome-i2svg-complete`
* HTML status class for active is added only after the first batch of icon replacements occur
* Added mention of newer versions of iOS in documentation FortAwesome/Font-Awesome-Pro#810

### Fixed
* Performance and missing features with mutation observer (should fix FortAwesome/Font-Awesome-Pro#813)
* Incorrect handling of icon class and style attributes when using autoReplace = &apos;nest&apos; FortAwesome/Font-Awesome-Pro#809
* Pseudo elements not added or removed when class mutations occur FortAwesome/Font-Awesome-Pro#821

---

## [5.0.0-rc3](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-rc3)  - 2017-10-13

### Added
* Node.js brand icon FortAwesome/Font-Awesome-Pro#779
* React brand icon FortAwesome/Font-Awesome-Pro#780
* OSI brand icon FortAwesome/Font-Awesome-Pro#748
* Add a class to the html element when icon replacement is complete FortAwesome/Font-Awesome-Pro#778
* Add support for symbols in API including ability to name the symbol
* Use CSS pseudo elements (:before and :after) to make trigger SVG replacements

### Changed
* Switched the locations of fork and knife in utensils-alt FortAwesome/Font-Awesome-Pro#466
* Updated the AWS brand icon FortAwesome/Font-Awesome-Pro#735
* Updated Apple App Store icon FortAwesome/Font-Awesome-Pro#728

### Fixed
* Do not throw an error if icon is missing when calling icon() method in API
* Ensure that unicode values do not change between releases
* Version field is missing in fontawesome-pro-brands/package.json FortAwesome/Font-Awesome-Pro#781
* Repeated commenting out of fa-layers when i2svg is called FortAwesome/Font-Awesome-Pro#788
* Title not showing up correctly for SVG FortAwesome/Font-Awesome-Pro#786

---

## [5.0.0-rc2](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-rc2)  - 2017-09-22

### Added
* Brand icons: accusoft, ns8, uniregistry

### Fixed
* Link to the npm package in the docs FortAwesome/Font-Awesome-Pro#729
* Incorrect reference to fontawesome-pro.js in docs

---

## [5.0.0-rc1](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-rc1)  - 2017-09-15

### Changed
* New Bitbucket logo FortAwesome/Font-Awesome-Pro#720
* Modifed the star icons to match use case better FortAwesome/Font-Awesome-Pro#710
* Switched names of css3 and css3-alt to reflect correct branding

### Fixed
* Correct whitespace with the Visa logo FortAwesome/Font-Awesome-Pro#719
* Improve OTF support by passing through FontForge FortAwesome/Font-Awesome-Pro#565
* Fonts with &quot;undefined&quot; name FortAwesome/Font-Awesome-Pro#711
* Shims will only function if using old prefix of &quot;fa&quot; FortAwesome/Font-Awesome-Pro#692
* Added missing &quot;youtube&quot; icon to categories

---

## [5.0.0-beta7](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta7)  - 2017-09-11

### Added
* Ability to nest the `&lt;svg&gt;` tag within the `&lt;i&gt;` FortAwesome/Font-Awesome-Pro#624
* Define icons as symbols and leverage SVG sprites FortAwesome/Font-Awesome-Pro#629
* Added alternative CSS3 logo FortAwesome/Font-Awesome-Pro#682

### Changed
* Power Transforms now execute inside the SVG instead of on the root element
* Filenames have changed to reflect a better division between Font Awesome Free and Pro

### Fixed
* More improvements to the version 4 shim FortAwesome/Font-Awesome-Pro#673 FortAwesome/Font-Awesome-Pro#678 FortAwesome/Font-Awesome-Pro#686 FortAwesome/Font-Awesome-Pro#687 FortAwesome/Font-Awesome-Pro#692
* Animation support for inline SVG now works as expected FortAwesome/Font-Awesome-Pro#662

---

## [5.0.0-beta6](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta6)  - 2017-09-01

### Added
* Ability to flip horizontal and vertical with CSS classes fa-flip-horizontal and fa-flip-vertical
* New film-alt icon that allows for layering other icons
* Microsoft brand

### Changed
* New YouTube branding FortAwesome/Font-Awesome-Pro#646

### Fixed
* Fixed a bunch of shim-related issues
* Cogs off center FortAwesome/Font-Awesome-Pro#663
* Corrected icons/categories.yml with canonical names

---

## [5.0.0-beta5](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta5)  - 2017-08-25

### Added
* Full parity with Font Awesome 4! 616 total core icons in each style
* 297 total brand and logo icons
* Separate CSS file to accompany the SVG Framework FortAwesome/Font-Awesome-Pro#627
* Alternative to the dots icon FortAwesome/Font-Awesome-Pro#608
* Made window icons consistent FortAwesome/Font-Awesome-Pro#611

### Fixed
* Production builds not correctly being detected FortAwesome/Font-Awesome-Pro#631

---

## [5.0.0-beta4](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta4)  - 2017-08-18

### Added
* 590 total core icons in each style
* 291 total brand and logo icons

### Fixed
* Reduced the size of JS file from 66 to 22 kb
* Regression caused by with web font alignment FortAwesome/Font-Awesome-Pro#460

---

## [5.0.0-beta3](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta3)  - 2017-08-15

### Added
* 583 total core icons in each style

### Fixed
* Documentation improvements and fixes FortAwesome/Font-Awesome-Pro#586
* Vertical alignment of TTF and OTF fonts FortAwesome/Font-Awesome-Pro#460
* The &quot;fa_500px&quot; icon should be named &quot;fa500px&quot; FortAwesome/Font-Awesome-Pro#578

---

## [5.0.0-beta2](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta2)  - 2017-08-11

### Added
* 570 total core icons in each style
* 291 total brand and logo icons
* NPM (ES6, CommonJS, AMD) packages for use with other JavaScript libraries and tools FortAwesome/Font-Awesome-Pro#574
* Added a guide to choosing which implementation is best for you FortAwesome/Font-Awesome-Pro#532

### Changed
* Showing a missing icon is now configurable FortAwesome/Font-Awesome-Pro#569

### Fixed
* Composition framework now works in browsers that do not support transform-origin FortAwesome/Font-Awesome-Pro#564

---

## [5.0.0-beta1](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-beta1)  - 2017-08-04

### Added
* 524 total core icons in each style
* 289 total brand and logo icons
* New composition framework FortAwesome/Font-Awesome-Pro#537
* Animated indicator if you use an icon that does not exist

### Changed
* Basic linting for Sass and Less files
* Add JavaScript guard block to prevent leaking errors
* Add support for automatic accessibility to SVG Framework Layers

### Fixed
* Regression where stacks and pulled and bordered were not working in SVG Framework
* SVG sprite example had confusing inline styles FortAwesome/Font-Awesome-Pro#549
* Make getting started page more consistent between examples FortAwesome/Font-Awesome-Pro#544
* Added missing sizes fa-[6-10], xs, sm FortAwesome/Font-Awesome-Pro#546
* Title tag missing in SVG sprites FortAwesome/Font-Awesome-Pro#536

---

## [5.0.0-alpha7](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha7)  - 2017-07-28

### Added
* 451 total core icons in each style
* 281 total brand and logo icons
* Less support is back!
* OpenType (.otf) file formats for web fonts

### Changed
* Changes the fa-spin animation to go from 0deg to 360deg to eliminate hitch FortAwesome/Font-Awesome-Pro#522
* Improved mutation handling FortAwesome/Font-Awesome-Pro#517

### Fixed
* fa-fw now works correctly with the SVG framework FortAwesome/Font-Awesome-Pro#530
* Removed execute bit on some icon files FortAwesome/Font-Awesome-Pro#520

---

## [5.0.0-alpha6](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha6)  - 2017-07-21

### Added
* 410 total core icons in each style
* 270 total brand and logo icons
* All new Font Awesome 4 shim file
* Beginnings of a public JS API FortAwesome/Font-Awesome-Pro#512

### Changed
* Added Firefox ESR and Chrome for Businesses to browser compatibility FortAwesome/Font-Awesome-Pro#506

### Fixed
* Ensure that SVG title attributes are unique
* Fixed incorrect viewBox sizes FortAwesome/Font-Awesome-Pro#492
* Fix chart-area alignment in the solid style FortAwesome/Font-Awesome-Pro#508
* Add missing xmlns attributes in some SVGs FortAwesome/Font-Awesome-Pro#509

---

## [5.0.0-alpha5](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha5)  - 2017-07-14

### Added
* 228 total brand and logo icons
* New transform framework for sizing, moving, rotating, and flipping icons
* New icon counters
* New layers framework
* New text overlays
* Auto-comments with the original source icons alongside SVG replacements

### Changed
* Autoprefixer to correctly add browser prefixes for supported browsers
* Removed browser-specific CSS properties in Sass source files (now relies on autoprefixer)

### Fixed
* The rotation on checkmark icons
* Other icon feedback from previous weeks
* Correct fixed width settings to 1.25em (based on the new 16px grid)
* Icons displaying as block instead of inline-block in IE and older Safari

---

## [5.0.0-alpha4](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha4)  - 2017-07-07

### Added
* 93 brand icons

---

## [5.0.0-alpha3](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha3)  - 2017-06-30

### Added
* 95 additional icons; including file types, directional, and some existing and new brand icons

### Fixed
* Wrong content type in generated CSS FortAwesome/Font-Awesome-Pro#458
* Removal of query string from static resources FortAwesome/Font-Awesome-Pro#458
* SVG font ID&apos;s are incorrect in webfont implementation FortAwesome/Font-Awesome-Pro#474

---

## [5.0.0-alpha2](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha2)  - 2017-06-27

### Added
* How/When to upgrade from FA4 to FA5 FortAwesome/Font-Awesome-Pro#454

### Fixed
* Links to SVG files broken in the example files FortAwesome/Font-Awesome-Pro#456
* Misnamed icon names in examples FortAwesome/Font-Awesome-Pro#445
* Mangled HTML in the Getting Started example FortAwesome/Font-Awesome-Pro#442
* Bad grammar and typos FortAwesome/Font-Awesome-Pro#443
* fas-arrow-to-top is identical to fas-arrow-to-right FortAwesome/Font-Awesome-Pro#423
* Vertical alignment issues with webfont implementation FortAwesome/Font-Awesome-Pro#444
* Add browser compatibility tables to demo FortAwesome/Font-Awesome-Pro#435
* Remove MAC OS feces from builds FortAwesome/Font-Awesome-Pro#437
* TTF naming issues that prevent correct usage/installation FortAwesome/Font-Awesome-Pro#450
* Correct CSS for SVG framework stacking, was reversed from normal FortAwesome/Font-Awesome-Pro#452

---

## [5.0.0-alpha1](https://github.com/FortAwesome/Font-Awesome-Pro/releases/tag/5.0.0-alpha1)  - 2017-06-23

### Added
* 300+ more icons
* Brands pack
* New JavaScript based SVG Framework
* New SVG Sprites based framework
* Source SVGs
* Documentation with a convenient build-in web server

### Changed
* New directory structure
</description>
            <link>https://aathawerani.github.io/assets/bower_components/font-awesome/CHANGELOG/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Upgrading Guide</title>
            <description># Upgrading Guide

See the [CHANGELOG.md](/assets/bower_components/font-awesome/CHANGELOG/) for detailed information about what has changed between versions.

This guide is useful to figure out what you need to do between breaking changes.

As always, [submit issues](https://github.com/FortAwesome/Font-Awesome/issues/new) that you run into with this guide or with these upgrades to us.

## 5.0.x to 5.1.0

### New packages available for browser-only integration

**If you were previously using @fortawesome/fontawesome you need to switch to one of the new packages.**

Our Free and Pro CDN provide access to JS, CSS, sprites, and separate SVG files.

We&apos;ve now made these files conveniently available through NPM.

* [@fortawesome/fontawesome-free](https://www.npmjs.com/package/@fortawesome/fontawesome-free)
* @fortawesome/fontawesome-pro (private package, requires Pro subscription)

If you are familiar with the paths and options available with the CDN these
packages should be familiar.

Information about [Font Awesome Pro subscriptions](https://fontawesome.com/pro)
can be found in your [Font Awesome awesome
account](https://fontawesome.com/account/services).

### Renamed packages

The following packages have been renamed as part of 5.1.0 of Font Awesome.

_All packages are in the [@fortawesome NPM scope](https://www.npmjs.com/search?q=scope:fortawesome&amp;page=1&amp;ranking=optimal)_

| Old package(1)            | New package            |
|---------------------------|------------------------|
| fontawesome-free-webfonts | fontawesome-free       |
| fontawesome-pro-webfonts  | fontawesome-pro        |
| fontawesome-free-solid    | free-solid-svg-icons   |
| fontawesome-free-regular  | free-regular-svg-icons |
| fontawesome-free-brands   | free-brands-svg-icons  |
| fontawesome-pro-solid     | pro-solid-svg-icons    |
| fontawesome-pro-regular   | pro-regular-svg-icons  |
| fontawesome-pro-light     | pro-light-svg-icons    |

(1) Old packages have now been deprecated. They are still available but will only receive high priority patch release fixes.

**You&apos;ll need to update your package.json file with the renamed packages and new versions.**

### No more default imports

Recently we spent a good deal of time supporting TypeScript to enable us to
create the Angular Font Awesome component. During that adventure we
[were](https://basarat.gitbooks.io/typescript/docs/tips/defaultIsBad.html)
[convinced](https://blog.neufund.org/why-we-have-banned-default-exports-and-you-should-do-the-same-d51fdc2cf2ad)
that we were going to remove default exports from all of our components,
libraries, and packages. This is complete with the umbrella release of `5.1.0` of Font Awesome.

What does that mean?

~~Old way:~~

```javascript
import fontawesome from &apos;@fortawesome/fontawesome&apos;
import solid from &apos;@fortawesome/fontawesome-free-solid&apos;
import faTwitter from &apos;@fortawesome/fontawesome-free-brands/faTwitter&apos;
import FontAwesomeIcon from &apos;@fortawesome/vue-fontawesome&apos;

library.add(solid, faTwitter)
```

New way:

```javascript
import { library, dom } from &apos;@fortawesome/fontawesome-svg-core&apos;
import { fas } from &apos;@fortawesome/free-solid-svg-icons&apos;
import { faTwitter } from &apos;@fortawesome/free-brands-svg-icons&apos;
import { FontAwesomeIcon } from &apos;@fortawesome/vue-fontawesome&apos;

library.add(fas, faTwitter)

// Kicks off the process of finding &lt;i&gt; tags and replacing with &lt;svg&gt;
dom.watch()
```

This is also a valid way to import icons that works if your tool does not support tree shaking:

```javascript
import { faTwitter } from &apos;@fortawesome/free-brands-svg-icons/faTwitter&apos;
```

### Improved support for tree shaking

Tree shaking is now functional by default and no additional configuration is required to make it work.

The `shakable.es.js` module has been removed and is no longer needed.

If you&apos;ve previously configured tree shaking by modifying your webpack or rollup you can safely remove these.

**We recommend that you check your bundle size after upgrading an ensure that file sizes are as you would expect.**

```javascript
module.exports = {
  // ...
  resolve: {
    alias: {
      &apos;@fortawesome/fontawesome-free-solid$&apos;: &apos;@fortawesome/fontawesome-free-solid/shakable.es.js&apos;
    }
  }
}
```

```javascript
const alias = require(&apos;rollup-plugin-alias&apos;)

rollup({
  // ...
  plugins: [
    alias({
      &apos;@fortawesome/fontawesome-free-solid&apos;: &apos;node_modules/@fortawesome/fontawesome-free-solid/shakable.es.js&apos;
    })
  ]
})
```

## 5.0.11 to 5.0.12

Due to a collision with the &quot;r&quot; glyph the R Project brand icon has been renamed to `r-project`.

## 5.0.x to 5.0.6

### SVG Attribute was changed from data-fa-processed to data-fa-i2svg

As part of a bug fix for the release of 5.0.6 we renamed an attribute that was found on `&lt;svg&gt;` elements from
`data-fa-processed` to `data-fa-i2svg`. We feel this more accurately reflects the intent and purpose.

This attribute is added to any icon that has been generated using `fontawesome.dom.i2svg()`.

Be aware that `data-fa-i2svg` (or `data-fa-processed`) will no longer be present on icons that are created using
`fontawesome.icon()`.

If you&apos;ve written and DOM queries that rely on `data-fa-processed` you should get things working again by doing a
simple find and replace.
</description>
            <link>https://aathawerani.github.io/assets/bower_components/font-awesome/UPGRADING/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Mouse Wheel ChangeLog</title>
            <description># Mouse Wheel ChangeLog

## 3.1.13

* Update copyright notice and license to remove years
* Create the correct compressed version
* Remove the obsolete jQuery Plugin Registry file

## 3.1.12

* Fix possible 0 value for line height when in delta mode 1

## 3.1.11

* Fix version number for package managers...

## 3.1.10

* Fix issue with calculating line height when using older versions of jQuery
* Add offsetX/Y normalization with setting to turn it off
* Cleans up data on teardown

## 3.1.9

* Fix bower.json file
* Updated how the deltas are adjusted for older mousewheel based events that have deltas that are factors of 120.
* Add $.event.special.mousewheel.settings.adjustOldDeltas (defaults to true) to turn off adjusting of old deltas that are factors of 120. You&apos;d turn this off if you want to be as close to native scrolling as possible.

## 3.1.8

* Even better handling of older browsers that use a wheelDelta based on 120
* And fix version reported by `$.event.special.mousewheel`

## 3.1.7

* Better handle the `deltaMode` values 1 (lines) and 2 (pages)
* Attempt to better handle older browsers that use a wheelDelta based on 120

## 3.1.6

* Deprecating `delta`, `deltaX`, and `deltaY` event handler arguments
* Update actual event object with normalized `deltaX `and `deltaY` values (`event.deltaX`, `event.deltaY`)
* Add `deltaFactor` to the event object (`event.deltaFactor`)
* Handle `&gt; 0` but `&lt; 1` deltas better
* Do not fire the event if `deltaX` and `deltaY` are `0`
* Better handle different devices that give different `lowestDelta` values
* Add `$.event.special.mousewheel.version`
* Some clean up

## 3.1.5

* Bad release because I did not update the new `$.event.special.mousewheel.version`

## 3.1.4

* Always set the `deltaY`
* Add back in the `deltaX` and `deltaY` support for older Firefox versions

## 3.1.3

* Include `MozMousePixelScroll` in the to fix list to avoid inconsistent behavior in older Firefox

## 3.1.2

* Include grunt utilities for development purposes (jshint and uglify)
* Include support for browserify
* Some basic cleaning up

## 3.1.1

* Fix rounding issue with deltas less than zero


## 3.1.0

* Fix Firefox 17+ issues by using new wheel event
* Normalize delta values
* Adds horizontal support for IE 9+ by using new wheel event
* Support AMD loaders


## 3.0.6

* Fix issue with delta being 0 in Firefox


## 3.0.5

* jQuery 1.7 compatibility


## 3.0.4

* Fix IE issue


## 3.0.3

* Added `deltaX` and `deltaY` for horizontal scrolling support (Thanks to Seamus Leahy)


## 3.0.2

* Fixed delta being opposite value in latest Opera
* No longer fix `pageX`, `pageY` for older Mozilla browsers
* Removed browser detection
* Cleaned up the code


## 3.0.1

* Bad release... creating a new release due to plugins.jquery.com issue :(


## 3.0

* Uses new special events API in jQuery 1.2.2+
* You can now treat `mousewheel` as a normal event and use `.bind`, `.unbind` and `.trigger`
* Using jQuery.data API for expandos


## 2.2

* Fixed `pageX`, `pageY`, `clientX` and `clientY` event properties for Mozilla based browsers


## 2.1.1

* Updated to work with jQuery 1.1.3
* Used one instead of bind to do unload event for clean up


## 2.1

* Fixed an issue with the unload handler


## 2.0

* Major reduction in code size and complexity (internals have change a whole lot)


## 1.0

* Fixed Opera issue
* Fixed an issue with children elements that also have a mousewheel handler
* Added ability to handle multiple handlers
</description>
            <link>https://aathawerani.github.io/assets/bower_components/jquery-mousewheel/ChangeLog/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Fizzy UI utils</title>
            <description># Fizzy UI utils

UI utility &amp; helper functions

Used in [Flickity](http://flickity.metafizzy.co), [Isotope](http://isotope.metafizzy.co), [Masonry](http://masonry.desandro.com), [Draggabilly](http://draggabilly.desandro.com)

## Install

Bower: `bower install fizzy-ui-utils --save`

npm: `npm install fizzy-ui-utils --save`

## API

``` js
// fizzyUIUtils is the browser global
var utils = fizzyUIUtils;

// ---- ---- //

utils.extend( a, b )
// extend object

utils.modulo( num, div )
// num [modulo] div

utils.makeArray( obj )
// make array from object

utils.removeFrom( ary, obj )
// remove object from array

utils.getParent( elem, selector )
// get parent element of an element, given a selector string

utils.getQueryElement( elem )
// if elem is a string, use it as a selector and return element

Class.prototype.handleEvent = utils.handleEvent;
// enable Class.onclick when element.addEventListener( &apos;click&apos;, this, false )

utils.filterFindElements( elems, selector )
// iterate through elems, filter and find all elements that match selector

utils.debounceMethod( Class, methodName, threhold )
// debounce a class method

utils.docReady( callback )
// trigger callback on document ready

utils.toDashed( str )
// &apos;camelCaseString&apos; -&gt; &apos;camel-case-string&apos;

utils.htmlInit( Class, namespace )
// on document ready, initialize Class on every element
// that matches js-namespace
// pass in JSON options from element&apos;s data-options-namespace attribute
```

---

[MIT license](http://desandro.mit-license.org/). Have at it.

By [Metafizzy](http://metafizzy.co)
</description>
            <link>https://aathawerani.github.io/assets/bower_components/fizzy-ui-utils/</link>
          </item>
        
      
    
      
        
          <item>
            <title>@fortawesome/free-regular-svg-icons - SVG with JavaScript version</title>
            <description># @fortawesome/free-regular-svg-icons - SVG with JavaScript version

&gt; &quot;I came here to chew bubblegum and install Font Awesome 5 - and I&apos;m all out of bubblegum&quot;

[![npm](https://img.shields.io/npm/v/@fortawesome/free-regular-svg-icons.svg?style=flat-square)](https://www.npmjs.com/package/@fortawesome/free-regular-svg-icons)

## Installation

```
$ npm i --save @fortawesome/free-regular-svg-icons
```

Or

```
$ yarn add @fortawesome/free-regular-svg-icons
```

## Documentation

Get started [here](https://fontawesome.com/get-started/svg-with-js). Continue your journey [here](https://fontawesome.com/how-to-use/svg-with-js).

Or go straight to the [API documentation](https://fontawesome.com/how-to-use/font-awesome-api).

## Issues and support

Start with [GitHub issues](https://github.com/FortAwesome/Font-Awesome/issues) and ping us on [Twitter](https://twitter.com/fontawesome) if you need to.
</description>
            <link>https://aathawerani.github.io/assets/bower_components/font-awesome/advanced-options/use-with-node-js/free-regular-svg-icons/</link>
          </item>
        
      
    
      
        
          <item>
            <title>jQuery Easing Plugin</title>
            <description># jQuery Easing Plugin

What is it? A jQuery plugin from GSGD to give advanced easing options. More info [here](http://gsgd.co.uk/sandbox/jquery/easing)

For CDN please use CloudFlare [`https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js`](https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js) to help my host. Thank you.

# AMD or CommonJS usage

```js
// CommonJS
var jQuery = require(&apos;jquery&apos;);
require(&apos;jquery.easing&apos;)(jQuery);

// AMD
define([&apos;jquery&apos;, &apos;jquery.easing&apos;], function (jQuery, easing) {
  easing(jQuery)
})
```

# Building and testing

* Clone the repo
* `npm install`
* Make changes
* Test against files in `/examples`
* Build minified version with `npm run build`
</description>
            <link>https://aathawerani.github.io/assets/bower_components/jquery.easing/</link>
          </item>
        
      
    
      
        
          <item>
            <title>jQuery</title>
            <description># jQuery

&gt; jQuery is a fast, small, and feature-rich JavaScript library.

For information on how to get started and how to use jQuery, please see [jQuery&apos;s documentation](http://api.jquery.com/).
For source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).

If upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.

## Including jQuery

Below are some of the most common ways to include jQuery.

### Browser

#### Script tag

```html
&lt;script src=&quot;https://code.jquery.com/jquery-3.3.1.min.js&quot;&gt;&lt;/script&gt;
```

#### Babel

[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.

```js
import $ from &quot;jquery&quot;;
```

#### Browserify/Webpack

There are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project&apos;s documention. In the script, including jQuery will usually look like this...

```js
var $ = require(&quot;jquery&quot;);
```

#### AMD (Asynchronous Module Definition)

AMD is a module format built for the browser. For more information, we recommend [require.js&apos; documentation](http://requirejs.org/docs/whyamd.html).

```js
define([&quot;jquery&quot;], function($) {

});
```

### Node

To include jQuery in [Node](nodejs.org), first install with npm.

```sh
npm install jquery
```

For jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.

```js
require(&quot;jsdom&quot;).env(&quot;&quot;, function(err, window) {
	if (err) {
		console.error(err);
		return;
	}

	var $ = require(&quot;jquery&quot;)(window);
});
```
</description>
            <link>https://aathawerani.github.io/assets/bower_components/jquery/</link>
          </item>
        
      
    
      
        
          <item>
            <title>Outlayer</title>
            <description># Outlayer

_Brains and guts of a layout library_

Outlayer is a base layout class for layout libraries like [Isotope](http://isotope.metafizzy.co), [Packery](http://packery.metafizzy.co), and [Masonry](http://masonry.desandro.com)

Outlayer layouts work with a container element and children item elements.

``` html
&lt;div class=&quot;grid&quot;&gt;
  &lt;div class=&quot;item&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;&lt;/div&gt;
  ...
&lt;/div&gt;
```

## Install

Install with [Bower](http://bower.io): `bower install outlayer`

[Install with npm](http://npmjs.org/package/outlayer): `npm install outlayer`

## Outlayer.create()

Create a layout class with `Outlayer.create()`

``` js
var Layout = Outlayer.create( namespace );
// for example
var Masonry = Outlayer.create(&apos;masonry&apos;);
```

+ `namespace` _{String}_ should be camelCased
+ returns `LayoutClass` _{Function}_

Create a new layout class. `namespace` is used for jQuery plugin, and for declarative initialization.

The `Layout` inherits from [`Outlayer.prototype`](docs/outlayer.md).

```
var elem = document.querySelector(&apos;.selector&apos;);
var msnry = new Masonry( elem, {
  // set options...
  columnWidth: 200
});
```

## Item

Layouts work with Items, accessible as `Layout.Item`. See [Item API](docs/item.md).

## Declarative

An Outlayer layout class can be initialized via HTML, by setting an attribute of `data-namespace` on the element. Options are set in JSON. For example:

``` html
&lt;!-- var Masonry = Outlayer.create(&apos;masonry&apos;) --&gt;
&lt;div class=&quot;grid&quot; data-masonry=&apos;{ &quot;itemSelector&quot;: &quot;.item&quot;, &quot;columnWidth&quot;: 200 }&apos;&gt;
  ...
&lt;/div&gt;
```

The declarative attributes and class will be dashed. i.e. `Outlayer.create(&apos;myNiceLayout&apos;)` will use `data-my-nice-layout` as the attribute.

## .data()

Get a layout instance from an element.

```
var myMasonry = Masonry.data( document.querySelector(&apos;.grid&apos;) );
```

## jQuery plugin

The layout class also works as jQuery plugin.

``` js
// create Masonry layout class, namespace will be the jQuery method
var Masonry = Outlayer.create(&apos;masonry&apos;);
// rock some jQuery
$( function() {
  // .masonry() to initialize
  var $grid = $(&apos;.grid&apos;).masonry({
    // options...
  });
  // methods are available by passing a string as first parameter
  $grid.masonry( &apos;reveal&apos;, elems );
});
```

## RequireJS

To use Outlayer with [RequireJS](http://requirejs.org/), you&apos;ll need to set some config.

Set [baseUrl](http://requirejs.org/docs/api.html#config-baseUrl) to bower_components and set a [path config](http://requirejs.org/docs/api.html#config-paths) for all your application code.

``` js
requirejs.config({
  baseUrl: &apos;bower_components&apos;,
  paths: {
    app: &apos;../&apos;
  }
});

requirejs( [ &apos;outlayer/outlayer&apos;, &apos;app/my-component.js&apos; ], function( Outlayer, myComp ) {
  new Outlayer( /*...*/ )
});
```

Or set a path config for all Outlayer dependencies.

``` js
requirejs.config({
  paths: {
    &apos;ev-emitter&apos;: &apos;bower_components/ev-emitter&apos;,
    &apos;get-size&apos;: &apos;bower_components/get-size&apos;,
    &apos;matches-selector&apos;: &apos;bower_components/matches-selector&apos;
  }
});
```

## MIT license

Outlayer is released under the [MIT license](http://desandro.mit-license.org).
</description>
            <link>https://aathawerani.github.io/assets/bower_components/outlayer/</link>
          </item>
        
      
    
      
    
      
    
      
    
      
    
      
    

  </channel>
</rss>