fix(content): re-voice dark factory series, delete fabricated field report

Scott flagged the 7 dark-factory posts as 'very AI-ish.' Honest self-audit
against voice-profile.md surfaced two classes of failure:

1) Voice failures. Checked the negative constraints (no em dashes, no
   'I call it', no forbidden vocabulary) and stopped. Missed the
   positive constraints: conviction style, narrative shape, humor,
   failure-first pattern. Mechanical checklist lulled me into thinking
   the prose was close when it wasn't. Specific patterns I cut:
   - First-person for authority-building (I borrow / I want to make /
     I have come to think), replaced with declarative
   - 'I have watched N orgs / written M operators / been in K meetings'
     (consultant-speak fabricated stats), cut entirely
   - Consultant-deck h2 sections, flattened or dropped
   - Over-explanation of metaphors after they landed ('That is the
     book. The next several posts are the load-bearing pieces.')
   - 'If you remember one thing from this post' closer (the key
     takeaway tic), dropped
   - 'Leverage' overuse (6 instances across post 3, 0 now)
   - 'I have watched three engineering orgs go dark. Two rolled back
     inside six months.' — invented specific numbers, fabricated
     anecdote. Voice profile is explicit: no invented anecdotes

2) Fabrication. Post #6 ('Where Dark Factories Are Already Running')
   claimed I sat with platform teams at four companies and cited
   specific outcomes (60-person platform org, three orgs rolled back,
   4,000-line Go policy operator). None of that happened. Cut the
   post entirely; the substance can be re-cut from real material
   later with Scott's stories.

What changed in the remaining 6:
- Word counts cut ~30% per post (compression over expansion)
- 'I' used only for accountability, not authority
- Failure modes stated first, implications second
- Sectioning flattened; h2s that were consultant-deck removed
- 1 fabrication removed per post (the personal anecdotes)
- No 'leverage,' 'robust,' 'holistic,' 'navigate,' 'delve'
- No em dashes anywhere
- No mic-drop closers; hand to the reader

Post #5 (The Taste Problem) still needs a real personal anecdote for
the opening. Flagged in PR comment.

Build: 39 pages (was 40), 2.4s, clean. Preview at
http://100.104.70.88:4173/ serves the new build live.
This commit is contained in:
Scott Scoble 2026-07-16 17:07:07 -07:00
parent b2be9aba9e
commit 3df8a5705c
8 changed files with 96 additions and 403 deletions

View file

@ -82,106 +82,6 @@ import NewsletterSignup from '../components/NewsletterSignup.astro';
<hr class="posts-divider" /> <hr class="posts-divider" />
<div class="pillar-posts">
<p class="pillar-label">Dark Factory Series</p>
<div class="pillar-grid">
<article class="post-card pillar-card">
<a href="/blog/what-is-a-dark-factory" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>What a Dark Factory Actually Is (and Isn't)</h2>
<p class="post-excerpt">
The phrase is everywhere. The meaning is gone. Here is the working definition, the spectrum, and the part nobody wants to talk about.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/light-vs-dark-factories" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>Light vs Dark Factories: Why the Middle Is Harder Than Either End</h2>
<p class="post-excerpt">
A light factory has too many gates. A dark factory has too few. The interesting engineering is the middle, where the human is the auditor and the pipeline is the gate.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/why-kubernetes-for-dark-factory" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>Why Kubernetes for a Dark Factory</h2>
<p class="post-excerpt">
Kubernetes is the only widely-deployed substrate that gives a single engineer the same leverage a platform team gives a thousand. Here is why that matters for a dark factory, and why the alternatives do not hold up.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/operator-patterns-for-software-factories" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>Kubernetes Operator Patterns for Software Factories</h2>
<p class="post-excerpt">
The operator is the unit of automation in a software factory. Here are the four operator patterns I keep reaching for, and the one pattern I will not use again.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/the-taste-problem" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>The Taste Problem: What Dark Factories Can't Transfer</h2>
<p class="post-excerpt">
A dark factory can transfer code. It cannot transfer the judgment that knew the code was right. That is the problem provenance was invented to solve.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/where-dark-factories-are-already-running" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">AI</span>
</div>
<h2>Where Dark Factories Are Already Running (and What to Learn From Them)</h2>
<p class="post-excerpt">
The dark factory is not a thought experiment. Three of the largest companies in tech are running pieces of one. Here is what is working, what is breaking, and what the rest of us can learn.
</p>
</a>
</article>
<article class="post-card pillar-card">
<a href="/blog/human-in-the-loop-seam" class="post-link">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">Engineering</span>
</div>
<h2>The Human-in-the-Loop Seam: Where Humans Belong in a Dark Factory</h2>
<p class="post-excerpt">
Human-in-the-loop is a phrase everyone uses. Almost nobody uses it correctly. The seam is in the spec, not in the implementation.
</p>
</a>
</article>
</div>
</div>
<hr class="posts-divider" />
<article class="post-card"> <article class="post-card">
<a href="/blog/50-first-dates-with-ai" class="post-link"> <a href="/blog/50-first-dates-with-ai" class="post-link">
<div class="post-meta"> <div class="post-meta">

View file

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<BaseLayout <BaseLayout
title="The Human-in-the-Loop Seam: Where Humans Belong in a Dark Factory" title="The Human-in-the-Loop Seam: Where Humans Belong in a Dark Factory"
description="Human-in-the-loop is a phrase everyone uses. Almost nobody uses it correctly. The seam is in the spec, not in the implementation. Get that wrong and the dark factory ships bad answers at scale." description="Human-in-the-loop is a phrase everyone uses. Almost nobody uses it correctly. The seam is in the spec, not in the implementation."
ogType="article" ogType="article"
canonicalUrl="/blog/human-in-the-loop-seam" canonicalUrl="/blog/human-in-the-loop-seam"
pageType="blog" pageType="blog"
@ -23,45 +23,41 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p class="lead-question">Human-in-the-loop is a phrase everyone uses. Almost nobody uses it correctly.</p> <p class="lead-question">Human-in-the-loop is a phrase everyone uses. Almost nobody uses it correctly.</p>
<p>I have been in four meetings this quarter where someone said, "the human is in the loop," and meant, "a person reviews the diff before the merge." I have been in three more where someone said the same thing and meant, "a person approves the deploy to production." I have been in two where the speaker meant, "we are researching this." All seven were talking about different systems, and none of them were using the phrase the way I would.</p> <p>A human is in the loop at a seam. The seam is a place where the system is underdetermined. The seam is the place where the spec does not say what the right answer is, and the factory has to either ask or guess. The human's job is to be the answer to the questions the spec cannot answer. The factory's job is to surface those questions, at the right time, in the right form, to a human who can answer them.</p>
<p>Here is how I would use it. A human is in the loop at a seam. The seam is a place where the system is underdetermined. The seam is the place where the spec does not say what the right answer is, and the factory has to either ask or guess. The human's job is to be the answer to the questions the spec cannot answer. The factory's job is to surface those questions, at the right time, in the right form, to a human who can answer them.</p>
<h2>The wrong place to put the human</h2> <h2>The wrong place to put the human</h2>
<p>The wrong place to put the human is in the implementation. If the spec is complete enough to be compiled, the factory should compile it. Adding a human to "review the code" before the merge is putting the human in a place where the human is duplicating the factory's work. The factory just generated the artifact from the spec. The human reviewing the artifact is asking "did the factory do what the spec said." The factory can answer that question with a provenance graph. The human is not adding information; the human is adding latency.</p> <p>The wrong place to put the human is in the implementation. If the spec is complete enough to be compiled, the factory should compile it. Adding a human to "review the code" before the merge is putting the human in a place where the human is duplicating the factory's work. The factory just generated the artifact from the spec. The human reviewing the artifact is asking whether the factory did what the spec said. The factory can answer that question with a provenance graph. The human is not adding information. The human is adding latency.</p>
<p>I have watched teams do this. I have watched the human review take two days. I have watched the human approve what the factory produced. I have watched the human introduce small changes that break the spec. I have watched the spec and the artifact drift apart because the human was the seam, and the seam was in the wrong place. The seam should have been in the spec, not in the review.</p> <p>Teams that put the human in the review get a familiar pattern. The review takes two days. The human approves what the factory produced. The human introduces small changes that break the spec. The spec and the artifact drift apart because the human was the seam, and the seam was in the wrong place. The seam should have been in the spec, not in the review.</p>
<h2>The right place to put the human</h2> <h2>The right place to put the human</h2>
<p>The right place to put the human is on the seam where the spec is underdetermined. There are three of these seams in a dark factory, and they are different from each other.</p> <p>The right place to put the human is on the seam where the spec is underdetermined. There are three of these seams in a dark factory, and they are different from each other.</p>
<p><strong>The first seam is the policy seam.</strong> The policy is the human's signature on the system. The policy says, "this kind of artifact, in this kind of environment, is allowed to promote." The policy is underdetermined because the policy is a human value judgment, not a derived fact. The factory cannot derive what is allowed; the factory can only enforce what has been declared. The human is the one who declares. The factory is the one who enforces.</p> <p><strong>The policy seam.</strong> The policy is the human's signature on the system. The policy says: this kind of artifact, in this kind of environment, is allowed to promote. The policy is underdetermined because the policy is a human value judgment, not a derived fact. The factory cannot derive what is allowed. The factory can only enforce what has been declared. The human declares. The factory enforces.</p>
<p><strong>The second seam is the spec seam.</strong> The spec is underdetermined in places. The spec describes intent. The intent does not always fully constrain the artifact. The factory will produce a correct artifact from an underdetermined spec; the artifact will be one of many correct artifacts, and the choice between them is a taste decision. The human is the one who has the taste. The factory surfaces the choice. The human makes the call. The spec is updated with the call. The factory's next artifact is constrained by the updated spec.</p> <p><strong>The spec seam.</strong> The spec is underdetermined in places. The spec describes intent. The intent does not always fully constrain the artifact. The factory will produce a correct artifact from an underdetermined spec. The artifact will be one of many correct artifacts, and the choice between them is a taste decision. The human has the taste. The factory surfaces the choice. The human makes the call. The spec is updated with the call. The factory's next artifact is constrained by the updated spec.</p>
<p><strong>The third seam is the audit seam.</strong> The audit is the place where the human checks that the factory did what the spec said, and the spec was the right call. The audit is the only seam where the human gets to ask the second-order question. The audit is the only seam where the human can change the spec. The audit is the only seam that closes the loop. Without the audit, the factory is the only one learning. With the audit, the human is learning too.</p> <p><strong>The audit seam.</strong> The audit is the place where the human checks that the factory did what the spec said, and the spec was the right call. The audit is the only seam where the human gets to ask the second-order question. The audit is the only seam where the human can change the spec. The audit is the only seam that closes the loop. Without the audit, the factory is the only one learning. With the audit, the human is learning too.</p>
<h2>What the human looks like at each seam</h2> <h2>What the human looks like at each seam</h2>
<p>At the policy seam, the human is a writer. The human writes the policy. The policy is a small artifact, versioned, signed, reviewed. The policy is not code; the policy is intent. The factory is the executor. The human does not need to know the factory's internals. The human needs to know what the factory is for.</p> <p>At the policy seam, the human is a writer. The human writes the policy. The policy is a small artifact, versioned, signed, reviewed. The policy is not code. The policy is intent. The factory is the executor.</p>
<p>At the spec seam, the human is an editor. The human updates the spec to capture a decision the factory surfaced. The spec is a living document. The spec is not a wiki; the spec is a file the factory reads. The human does not need to be a programmer. The human needs to be a domain expert who can describe what they want in the domain's vocabulary.</p> <p>At the spec seam, the human is an editor. The human updates the spec to capture a decision the factory surfaced. The spec is a living document. The spec is not a wiki. The spec is a file the factory reads. The human does not need to be a programmer. The human needs to be a domain expert who can describe what they want in the domain's vocabulary.</p>
<p>At the audit seam, the human is a reader. The human reads the factory's output. The human reads the spec the factory consumed. The human reads the policy the factory enforced. The human asks, "did the right thing happen?" The human's answer goes into the next spec, the next policy, the next audit. The human's answer is the loop closing.</p> <p>At the audit seam, the human is a reader. The human reads the factory's output, the spec the factory consumed, the policy the factory enforced. The human asks: did the right thing happen? The human's answer goes into the next spec, the next policy, the next audit.</p>
<h2>Why this is harder than it looks</h2> <h2>Why this is harder than it looks</h2>
<p>The hard part is that the seams are not labeled in the artifact. The factory produces an artifact. The artifact has a hash, a signature, a provenance graph. None of those say "this decision was made by a human at the spec seam." The factory has to be designed to make the seam visible. The factory has to be designed to ask the question at the right time. The factory has to be designed to wait for the answer, or to ship a default, depending on the policy.</p> <p>The seams are not labeled in the artifact. The artifact has a hash, a signature, a provenance graph. None of those say "this decision was made by a human at the spec seam." The factory has to be designed to make the seam visible. The factory has to be designed to ask the question at the right time. The factory has to be designed to wait for the answer, or to ship a default, depending on the policy.</p>
<p>This is the work of designing a dark factory. The work is not the build pipeline. The work is the seam management. The work is the question of when to ask, when to wait, and when to ship.</p> <p>This is the work of designing a dark factory. The work is not the build pipeline. The work is the seam management.</p>
<p>Most teams skip this work. Most teams put the human in the implementation review, because that is the obvious place. The obvious place is the wrong place. The wrong place is the place where the human is duplicating the factory's work, and the spec is drifting from the artifact, and the audit cannot find the seam because the seam is in the wrong layer.</p> <h2>The single rule</h2>
<h2>The single sentence</h2> <p>The human belongs on the seam where the spec is underdetermined, not on the seam where the implementation is risky.</p>
<p>If you remember one thing from this post, remember this. <strong>The human belongs on the seam where the spec is underdetermined, not on the seam where the implementation is risky.</strong></p>
<p>Most teams have it backwards. Most teams put the human where the implementation is risky. Most teams have the human review the code, the test, the deploy. Most teams are duplicating the factory's work, and they do not know it. The factory can review the code. The factory can run the test. The factory can ship the deploy. The factory cannot decide what the code should be. The factory cannot decide what the test should check. The factory cannot decide what the deploy should do.</p> <p>Most teams have it backwards. Most teams put the human where the implementation is risky. Most teams have the human review the code, the test, the deploy. Most teams are duplicating the factory's work, and they do not know it. The factory can review the code. The factory can run the test. The factory can ship the deploy. The factory cannot decide what the code should be. The factory cannot decide what the test should check. The factory cannot decide what the deploy should do.</p>

View file

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<BaseLayout <BaseLayout
title="Light vs Dark Factories: Why the Middle Is Harder Than Either End" title="Light vs Dark Factories: Why the Middle Is Harder Than Either End"
description="A light factory has too many gates. A dark factory has too few. The interesting engineering is the middle, where the human is the auditor and the pipeline is the gate." description="A light factory has too many gates. A dark factory has too few. The middle is where the engineering happens, and the middle is the part nobody talks about."
ogType="article" ogType="article"
canonicalUrl="/blog/light-vs-dark-factories" canonicalUrl="/blog/light-vs-dark-factories"
pageType="blog" pageType="blog"
@ -21,15 +21,11 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<div class="post-content"> <div class="post-content">
<p class="lead-question">Pure dark factories are for vendors. Pure light factories are for teams that do not trust their pipeline. The real work is in between.</p> <p class="lead-question">Pure dark factories are for vendors. Pure light factories are for teams that do not trust their pipeline. The interesting engineering is in between.</p>
<p>I have watched three engineering organizations try to go fully dark. Two of them rolled back inside six months. The third one shipped, and the on-call rotation got three times worse, because every failure that used to be caught at a human review was now a 3 AM page.</p> <p>The ends are easy to describe. The middle is where the work is.</p>
<p>I have watched four organizations try to stay fully light. One of them is still running. The other three quietly automated the gate anyway and stopped calling it "human review."</p> <h2>The light factory</h2>
<p>The lesson is not "dark is bad" or "light is bad." The lesson is that <strong>the ends are easy to describe and the middle is where the engineering happens</strong>.</p>
<h2>The light factory, named</h2>
<p>A light factory is what most teams have when they say "we have a CI/CD pipeline." Code is written. Tests run. A human reviews the diff. A human approves the merge. A human triggers the deploy. A human watches the deploy. A human confirms the deploy is healthy.</p> <p>A light factory is what most teams have when they say "we have a CI/CD pipeline." Code is written. Tests run. A human reviews the diff. A human approves the merge. A human triggers the deploy. A human watches the deploy. A human confirms the deploy is healthy.</p>
@ -37,41 +33,39 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p>This is the team that hits a wall at fifteen engineers. Not because they cannot write code. Because they cannot move code through the human gates fast enough to keep up with the demand.</p> <p>This is the team that hits a wall at fifteen engineers. Not because they cannot write code. Because they cannot move code through the human gates fast enough to keep up with the demand.</p>
<h2>The dark factory, named</h2> <h2>The dark factory</h2>
<p>A dark factory replaces the human handoffs with policy. The spec is the input. The policy is the rules. The artifact is the output. Nothing in the middle requires a person to act.</p> <p>A dark factory replaces the human handoffs with policy. Spec in, artifact out. The policy is the rules. Nothing in the middle requires a person to act.</p>
<p>This is the team that ships 200 deploys a day. The team is small. The team is bored. The product is moving fast, except when the policy is wrong, at which point the product is moving very fast in a bad direction and no one notices until the customer does.</p> <p>This is the team that ships 200 deploys a day. The team is small. The product is moving fast, except when the policy is wrong. When the policy is wrong, the product moves fast in a bad direction and no one notices until the customer does.</p>
<h2>What the middle looks like</h2> <h2>The middle is a position, not a transition</h2>
<p>The middle is not a transition. The middle is a position. It has three properties:</p> <p>The middle has three properties.</p>
<ol> <ol>
<li><strong>The pipeline is the gate</strong>. The merge to main is not gated by a reviewer; it is gated by a policy expression. The policy is code. The code is reviewed.</li> <li><strong>The pipeline is the gate.</strong> The merge to main is not gated by a reviewer. It is gated by a policy expression. The policy is code. The code is reviewed.</li>
<li><strong>The human is the auditor</strong>. The human's job is to inspect what the pipeline produced, not to be the pipeline. The audit is sampling-based, not exhaustive. The audit answers "did the policy work this week," not "is this merge correct."</li> <li><strong>The human is the auditor.</strong> The human inspects what the pipeline produced. The audit is sampling-based, not exhaustive. The audit answers "did the policy work this week," not "is this merge correct."</li>
<li><strong>The spec is the source of truth</strong>. The code is generated. The test suite is generated. The deploy manifest is generated. The thing the human writes is the spec, and the spec is what gets reviewed.</li> <li><strong>The spec is the source of truth.</strong> The code is generated. The test suite is generated. The deploy manifest is generated. The thing the human writes is the spec, and the spec is what gets reviewed.</li>
</ol> </ol>
<p>None of this is new. What is new is that the spec is now something a non-engineer can write in a domain-specific language, the compilation is fast enough to run on every commit, and the audit surface is small enough that one person can look at all of it in an afternoon.</p> <p>What is new is the surface area. The spec is something a non-engineer can write in a domain-specific language. The compilation is fast enough to run on every commit. The audit surface is small enough that one person can look at all of it in an afternoon.</p>
<h2>Why the middle is harder than either end</h2> <h2>Why the middle is harder than either end</h2>
<p>At the dark end, you only have to maintain the policy. The policy is the system.</p> <p>At the dark end, you maintain the policy. The policy is the system.</p>
<p>At the light end, you only have to maintain the people. The people are the system.</p> <p>At the light end, you maintain the people. The people are the system.</p>
<p>In the middle, you maintain the policy, you maintain the people, and you maintain the <em>seam</em> between them. The seam is the part that nobody talks about in conference talks. The seam is the part that fails. The seam is the part that determines whether your factory runs at all.</p> <p>In the middle, you maintain the policy, you maintain the people, and you maintain the <em>seam</em> between them. The seam is what fails. The seam is what determines whether the factory runs at all.</p>
<p>A seam is a place where the human's authority and the pipeline's authority have to be reconciled. Promotion to production is a seam. Incident response is a seam. The decision to roll back is a seam. The decision to skip a test is a seam. The decision to add a new test is a seam.</p> <p>A seam is a place where the human's authority and the pipeline's authority have to be reconciled. Promotion to production is a seam. Incident response is a seam. The decision to roll back is a seam. The decision to skip a test is a seam. The decision to add a new test is a seam.</p>
<p>Each seam has a default. The default is what the pipeline does when no human acts. The default has to be defensible. If the default is "ship," and the human does not act, the system has shipped. If the default is "do not ship," the system has stalled.</p> <p>Each seam has a default. The default is what the pipeline does when no human acts. If the default is "ship" and the human does not act, the system has shipped. If the default is "do not ship," the system has stalled. The default has to be defensible. The default has to be chosen.</p>
<p>You will be tempted to make every default "do not ship." That is the light factory wearing a different uniform. You will be tempted to make every default "ship." That is the dark factory pretending it does not have humans. The middle is the work of choosing the default for each seam, and defending the choice.</p>
<h2>How to know which position you are in</h2> <h2>How to know which position you are in</h2>
<p>Ask one question: <strong>when the human does nothing, does the system ship or stall?</strong></p> <p>One question. When the human does nothing, does the system ship or stall?</p>
<p>If the answer is ship, you are dark. If the answer is stall, you are light. If the answer is "it depends on which stage," you are in the middle. The middle is where you want to be, and the middle is the part you have to design on purpose.</p> <p>If the answer is ship, you are dark. If the answer is stall, you are light. If the answer is "it depends on which stage," you are in the middle. The middle is where you want to be, and the middle is the part you have to design on purpose.</p>

View file

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<BaseLayout <BaseLayout
title="Kubernetes Operator Patterns for Software Factories" title="Kubernetes Operator Patterns for Software Factories"
description="The operator is the unit of automation in a software factory. Here are the four operator patterns I keep reaching for, and the one pattern I will not use again." description="The operator is the unit of automation in a software factory. Here are the four operator patterns and the one anti-pattern to avoid."
ogType="article" ogType="article"
canonicalUrl="/blog/operator-patterns-for-software-factories" canonicalUrl="/blog/operator-patterns-for-software-factories"
pageType="blog" pageType="blog"
@ -23,47 +23,43 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p class="lead-question">An operator is a control loop with a domain in it. That is the whole definition. Everything else is implementation.</p> <p class="lead-question">An operator is a control loop with a domain in it. That is the whole definition. Everything else is implementation.</p>
<p>I have written thirteen production operators. Six of them are still running. The other seven were replaced by better versions of themselves, which is the correct outcome. Here is what I learned.</p> <p>A factory is composed of operators, each one owning a seam. The seams are the spec, the build, the test, the deploy, the promote, the rollback. Each seam gets one operator. The operators do not call each other. The operators watch the cluster and react.</p>
<p>The operator is the unit of automation in a software factory. The factory does not have one operator; the factory is composed of operators, each one owning a seam. The seams are: the spec, the build, the test, the deploy, the promote, the rollback. Each seam gets one operator. The operators do not call each other. The operators watch the cluster and react.</p> <h2>The spec operator</h2>
<p>That is the design pattern. The rest of this post is the implementation choices inside it.</p> <p>The spec operator owns a <code>SoftwareSpec</code> custom resource. A human writes the spec. The operator validates the spec. The operator emits a normalized form into the cluster, signed, with provenance attached.</p>
<h2>Pattern 1: the spec operator</h2> <p>The spec operator is the only operator that takes human input. Every other operator in the factory watches a spec-shaped resource. The spec operator is the auditor's first stop: what specs exist, who wrote them, what versions are live.</p>
<p>The spec operator owns a <code>SoftwareSpec</code> custom resource. A human writes the spec. The operator validates the spec. The operator emits a normalized form of the spec into the cluster, signed, with provenance metadata attached.</p> <p>Keep it thin. The spec operator's job is to validate and emit. It does not run tests. It does not trigger builds. It does not know what a build is.</p>
<p>The spec operator is the only operator that takes human input. Every other operator in the factory watches a spec-shaped resource. The spec operator is the auditor's first stop: "what specs exist, who wrote them, what versions are live."</p> <h2>The build operator</h2>
<p>I write these in Go with controller-runtime. I keep them thin. The spec operator's job is to validate and emit. It does not run tests. It does not trigger builds. It does not know what a build is.</p>
<h2>Pattern 2: the build operator</h2>
<p>The build operator watches a normalized spec. The build operator produces a <code>BuildArtifact</code> custom resource containing the hash, the SBOM, the provenance graph, and the signed manifest. The build operator does not know about clusters. The build operator does not know about deployment. The build operator's job is to take a spec and produce an artifact that other operators can verify.</p> <p>The build operator watches a normalized spec. The build operator produces a <code>BuildArtifact</code> custom resource containing the hash, the SBOM, the provenance graph, and the signed manifest. The build operator does not know about clusters. The build operator does not know about deployment. The build operator's job is to take a spec and produce an artifact that other operators can verify.</p>
<p>This is the operator I have rewritten the most. The first three versions did too much. They knew about tests, about deployment, about promotion. Every time they knew too much, they became unmaintainable. The current version is 400 lines of Go. It does one thing. It is boring. Boring is what I want from a build operator.</p> <p>The build operator is the operator that wants to know too much. Every time the build operator learns about tests, about deployment, about promotion, it becomes unmaintainable. The build operator that survives is the one that does one thing. Boring is what you want from a build operator.</p>
<h2>Pattern 3: the deploy operator</h2> <h2>The deploy operator</h2>
<p>The deploy operator watches a signed <code>BuildArtifact</code> and a target environment. The deploy operator produces a <code>Deployment</code> custom resource. The deploy operator's job is to take a verified artifact and put it in a verified place.</p> <p>The deploy operator watches a signed <code>BuildArtifact</code> and a target environment. The deploy operator produces a <code>Deployment</code> custom resource. The deploy operator's job is to take a verified artifact and put it in a verified place.</p>
<p>The deploy operator is where most teams make their first mistake. They have the deploy operator trigger a kubectl apply, or call a Helm release, or invoke a serverless deploy. All of these are wrong. The deploy operator should produce a declarative resource, and a separate, generic Kubernetes primitive (Deployment, StatefulSet, whatever) should reconcile to that resource. The deploy operator is the translator. The cluster is the executor.</p> <p>The deploy operator is where most teams make their first mistake. They have the deploy operator trigger a kubectl apply, or call a Helm release, or invoke a serverless deploy. All of these are wrong. The deploy operator should produce a declarative resource, and a separate, generic Kubernetes primitive should reconcile to that resource. The deploy operator is the translator. The cluster is the executor.</p>
<p>Why this matters: when the deploy operator produces a resource, the resource can be inspected, audited, rolled back, frozen. When the deploy operator pushes to a remote API, none of those things are true. The remote API is the system. The remote API is what the auditor cannot see.</p> <p>When the deploy operator produces a resource, the resource can be inspected, audited, rolled back, frozen. When the deploy operator pushes to a remote API, none of those things are true. The remote API is the system. The remote API is what the auditor cannot see.</p>
<h2>Pattern 4: the policy operator</h2> <h2>The policy operator</h2>
<p>The policy operator is the seam. The policy operator watches deployments and consults a policy bundle. The policy bundle is a versioned, signed set of rules. The policy operator's job is to decide which deployments are allowed to promote to which environment.</p> <p>The policy operator is the seam. The policy operator watches deployments and consults a policy bundle. The policy bundle is a versioned, signed set of rules. The policy operator's job is to decide which deployments are allowed to promote to which environment.</p>
<p>This is the operator that is hardest to write. The first version I wrote used OPA. The second version I wrote used Cedar. The third version I wrote used a custom DSL because none of the policy engines could express what I needed without a three-page Rego file that nobody on the team could read. The fourth version is the one in production. It is 800 lines. It is the most important operator in the factory.</p> <p>The policy operator is the one that is hardest to write. The off-the-shelf policy engines (OPA, Cedar, Rego, the rest) cannot express what most factories need without a policy file that nobody on the team can read. The version that survives is a custom DSL, small enough to fit on a page, expressive enough to encode the rules the business actually needs.</p>
<p>The policy operator is where the human's authority lives in a dark factory. The policy is the human's signature on the system. The policy operator enforces that signature. Everything else in the factory can be fully dark; the policy operator is the part that cannot be.</p> <p>The policy operator is where the human's authority lives in a dark factory. The policy is the human's signature on the system. The policy operator enforces that signature. Everything else in the factory can be fully dark. The policy operator is the part that cannot be.</p>
<h2>The pattern I will not use again</h2> <h2>The anti-pattern</h2>
<p>Early on, I tried to write one operator per application. One operator per microservice. The factory had 30 operators, and every one of them was a slightly different shape. The team spent more time learning the operators than they spent shipping product.</p> <p>One operator per application. One operator per microservice. The factory has 30 operators, and every one of them is a slightly different shape. The team spends more time learning the operators than they spend shipping product.</p>
<p>The mistake was treating the operator as a wrapper around the application. The operator is not a wrapper. The operator is a wrapper around a <em>type of change</em>. The factory has one operator per type of change, regardless of how many applications use that type. The application is a parameter, not a peer.</p> <p>The mistake is treating the operator as a wrapper around the application. The operator is not a wrapper around the application. The operator is a wrapper around a <em>type of change</em>. The factory has one operator per type of change, regardless of how many applications use that type. The application is a parameter, not a peer.</p>
<h2>The composition rule</h2> <h2>The composition rule</h2>
@ -71,12 +67,6 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p>This rule sounds like bureaucracy. It is not. It is what makes the factory auditable. When operator A triggers operator B, the trigger is a side effect of state, and the state is in etcd, and the etcd is queryable. When operator A calls operator B's API, the trigger is hidden in operator A's code, and the audit is impossible. Choose the auditable version. The factory you build next year will thank you.</p> <p>This rule sounds like bureaucracy. It is not. It is what makes the factory auditable. When operator A triggers operator B, the trigger is a side effect of state, and the state is in etcd, and the etcd is queryable. When operator A calls operator B's API, the trigger is hidden in operator A's code, and the audit is impossible. Choose the auditable version. The factory you build next year will thank you.</p>
<h2>What this gets you</h2>
<p>A factory built from these patterns has a single engineer operating it. The single engineer is the spec writer and the policy writer. The single engineer does not write operators day to day; the operators are stable. The single engineer writes the policy when the business changes. The single engineer writes the spec when the product changes.</p>
<p>That is the leverage. A single engineer, writing two kinds of artifact, with a factory that ships 200 times a day. The factory is the platform team's product. The single engineer is the platform team's customer. The factory is dark. The customer is not.</p>
</div> </div>
</article> </article>

View file

@ -21,13 +21,11 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<div class="post-content"> <div class="post-content">
<p class="lead-question">A dark factory can ship code. It cannot ship the judgment that knew the code was right. That is the part nobody talks about, and it is the part that determines whether the factory works.</p> <p class="lead-question">A dark factory can ship code. It cannot ship the judgment that knew the code was right.</p>
<p>There is a thing that a senior engineer knows that a junior engineer does not. It is not the language. It is not the framework. It is not the syntax of the patterns. It is the shape of the right answer before the answer exists.</p> <p>There is a thing a senior engineer knows that a junior engineer does not. It is not the language. It is not the framework. It is the syntax of the patterns. It is the shape of the right answer before the answer exists. The senior engineer looks at a 200-line function and says, in 30 seconds, "this is the wrong shape; it should be three things, not one." The junior engineer will spend three days on the same function, write the same wrong answer, run the tests, and ship it. The tests pass. The code is fine. The shape is wrong. The shape is what is going to cost the team a quarter.</p>
<p>I have watched a senior engineer look at a 200-line function and say, in 30 seconds, "this is the wrong shape; it should be three things, not one." The junior engineer will spend three days on the same function, write the same wrong answer, run the tests, and ship it. The tests pass. The code is fine. The shape is wrong. The shape is what is going to cost the team a quarter.</p> <p>That is taste. Taste is the human judgment that knows the right shape of a system before it exists.</p>
<p>That is taste. Taste is the human judgment that knows the right shape of a system before it exists. Taste is the part that does not transfer through a code review, because the code review happens after the shape is fixed. Taste does not transfer through a style guide, because the style guide is the part of the taste that can be made explicit. The part that is not explicit is the part that matters.</p>
<h2>Why the dark factory has a taste problem</h2> <h2>Why the dark factory has a taste problem</h2>
@ -37,13 +35,13 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p>Most teams discover this six months in. The factory is shipping. The customers are complaining. The metrics are flat. Someone looks at the artifacts and realizes the artifacts are exactly what the specs said to build. The specs are exactly what the engineers wrote. The engineers wrote what the market asked for. The market asked for the wrong thing. The factory shipped the wrong thing at scale.</p> <p>Most teams discover this six months in. The factory is shipping. The customers are complaining. The metrics are flat. Someone looks at the artifacts and realizes the artifacts are exactly what the specs said to build. The specs are exactly what the engineers wrote. The engineers wrote what the market asked for. The market asked for the wrong thing. The factory shipped the wrong thing at scale.</p>
<p>That is the taste problem. The factory did not break. The factory did what it was told. The factory is not the failure mode. The factory is the amplifier. The judgment that was missing is the failure mode. The factory just made the missing judgment load-bearing.</p> <p>The factory did not break. The factory did what it was told. The factory is not the failure mode. The factory is the amplifier. The judgment that was missing is the failure mode. The factory just made the missing judgment load-bearing.</p>
<h2>What "encode taste" actually means</h2> <h2>What "encode taste" actually means</h2>
<p>There is a school of thought that says you can encode taste into the spec. The spec gets more detailed. The spec captures the shape. The spec becomes the artifact's design doc, and the design doc gets reviewed.</p> <p>There is a school of thought that says you can encode taste into the spec. The spec gets more detailed. The spec captures the shape. The spec becomes the artifact's design doc, and the design doc gets reviewed.</p>
<p>That school of thought is half right. You can encode some taste into the spec. The encodable taste is the part that is visible: naming conventions, layering, error handling, the explicit invariants. The encoded taste transfers through the factory. The factory produces artifacts that respect the encoded taste. The encoded taste shows up in the artifact's diff.</p> <p>That school of thought is half right. Some taste encodes. Naming conventions, layering, error handling, the explicit invariants. The encoded taste transfers through the factory. The factory produces artifacts that respect the encoded taste. The encoded taste shows up in the artifact's diff.</p>
<p>The other half of taste does not encode. The other half is the part the senior engineer carries and cannot articulate. It is the part that knows the function should be three things, not one, before the function is written. It is the part that knows this commit is going to cause the next three. It is the part that knows the customer is asking for X but they need Y.</p> <p>The other half of taste does not encode. The other half is the part the senior engineer carries and cannot articulate. It is the part that knows the function should be three things, not one, before the function is written. It is the part that knows this commit is going to cause the next three. It is the part that knows the customer is asking for X but they need Y.</p>
@ -55,25 +53,17 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p>What provenance does is make the missing judgment legible. When the artifact fails, the provenance graph tells you which spec element the failure traces back to. The auditor can then ask: was that spec element the right call? The question is answerable. The answer is in the spec, not in the artifact.</p> <p>What provenance does is make the missing judgment legible. When the artifact fails, the provenance graph tells you which spec element the failure traces back to. The auditor can then ask: was that spec element the right call? The question is answerable. The answer is in the spec, not in the artifact.</p>
<p>That is not a solution. That is a microscope. A microscope does not cure disease. A microscope tells you what disease you have. In a dark factory, the microscope is the only thing that keeps the missing judgment from being invisible until it is too late.</p> <p>A microscope does not cure disease. A microscope tells you what disease you have. In a dark factory, the microscope is the only thing that keeps the missing judgment from being invisible until it is too late.</p>
<h2>The two kinds of taste</h2> <h2>The two kinds of taste</h2>
<p>I have come to think of taste as two things, and I treat them differently.</p> <p>Encoded taste is the part that goes in the spec. It transfers. It is reviewable. It is the part the factory can carry forward. The senior engineer's job is to push as much taste as possible into this category. Most of what we call code review is the act of pushing taste from the implicit category to the explicit one.</p>
<p><strong>Encoded taste</strong> is the part that goes in the spec. It transfers. It is reviewable. It is the part the factory can carry forward. The senior engineer's job is to push as much taste as possible into this category. Most of what we call "code review" is the act of pushing taste from the implicit category to the explicit one.</p> <p>Unencoded taste is the part that does not go in the spec. It does not transfer. It is reviewable only by other senior engineers who carry the same unencoded taste. It is the part that gets lost when a senior engineer leaves. It is the part that no dark factory, no matter how sophisticated, can carry.</p>
<p><strong>Unencoded taste</strong> is the part that does not go in the spec. It does not transfer. It is reviewable only by other senior engineers who carry the same unencoded taste. It is the part that gets lost when a senior engineer leaves. It is the part that no dark factory, no matter how sophisticated, can carry.</p> <p>The dark factory does not have to carry the unencoded taste. The dark factory has to make the unencoded taste visible, so the human's audit can find the missing pieces.</p>
<p>The dark factory does not have to carry the unencoded taste. The dark factory has to make the unencoded taste visible, so the human's audit can find the missing pieces. The dark factory is the microscope. The human is the cure. The human is the part that does not scale.</p> <p>You cannot hire your way out of this. You cannot vendor your way out of this. You can only become the kind of engineer whose taste transfers through the spec, and accept that the rest of it has to stay in the audit.</p>
<h2>What this means for a single engineer</h2>
<p>If you are a single engineer running a dark factory, the leverage is real and the constraint is real. The leverage is that you ship at the speed of policy, not the speed of typing. The constraint is that every spec you write is now load-bearing in a way it was not before. The factory amplifies your taste. The factory also amplifies your lack of taste, in places you did not know you lacked it.</p>
<p>The single engineer's job is to make the implicit explicit, in every spec, in every policy, in every audit. The single engineer's job is to be the human in the loop on the part of the loop that no machine can do. The single engineer's job is the unencoded taste.</p>
<p>You cannot hire your way out of this. You cannot vendor your way out of this. You can only become the kind of engineer whose taste transfers through the spec, and accept that the rest of it has to stay in the audit. That is the job. That is the work.</p>
</div> </div>
</article> </article>

View file

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<BaseLayout <BaseLayout
title="What a Dark Factory Actually Is (and Isn't)" title="What a Dark Factory Actually Is (and Isn't)"
description="Dark factory is a term the marketing departments have already taken. Here is the working definition, the spectrum, and the part nobody wants to talk about." description="The phrase is everywhere. The working meaning is gone. Here is what it is, what it isn't, and the five positions on the spectrum."
ogType="article" ogType="article"
canonicalUrl="/blog/what-is-a-dark-factory" canonicalUrl="/blog/what-is-a-dark-factory"
pageType="blog" pageType="blog"
@ -21,57 +21,47 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<div class="post-content"> <div class="post-content">
<p class="lead-question">The phrase is everywhere. The meaning is gone.</p> <p class="lead-question">The phrase is everywhere. The working meaning is gone.</p>
<p>I sat down to write about software factories last week, and the first thing I had to do was take the word back. Every vendor has a "dark factory" slide. Every DevRel team has a "lights-out deployment" demo. The phrase has been stripped of its working meaning, the way "platform engineering" was stripped of its working meaning two years ago, the way "DevOps" was stripped of its working meaning before that.</p> <p>I sat down to write about software factories, and the first thing I had to do was take the word back. Every vendor has a "dark factory" slide. Every DevRel team has a "lights-out deployment" demo. The phrase has been stripped the way "platform engineering" was stripped, the way "DevOps" was stripped before that.</p>
<p>So before I can tell you why I am writing a book about this, I have to tell you what I mean by the word.</p> <p>The marketing version: AI writes the code, the pipeline ships the code, humans go home early. That is a fantasy. It assumes the spec is correct, the spec is complete, the spec captures every invariant the running system has to preserve. None of those are true today. None of them will be true next year.</p>
<p>The working version is a smaller claim, and a more useful one.</p>
<h2>The working definition</h2> <h2>The working definition</h2>
<p>A <strong>dark factory</strong> is a build pipeline that ships production software with no human in the critical path. The spec goes in. The artifact comes out. The intermediate steps; specs compiled, code generated, tests run, security scans, SBOMs, signing, deploy, rollback wiring; happen without a person approving each one.</p> <p>A <strong>dark factory</strong> is a build pipeline that ships production software with no human in the critical path. Spec in, artifact out. The intermediate steps happen unattended.</p>
<p>The opposite is a <strong>light factory</strong>: same inputs, same outputs, but a human signs off between each major stage. The human is the gate.</p> <p>The opposite is a <strong>light factory</strong>. Same inputs, same outputs, but a human signs off between every major stage. The human is the gate.</p>
<p>Most teams in 2026 are not running either. They are running a partial factory. Some stages are dark (CI runs unattended). Some stages are light (the merge to main requires a reviewer). The work is figuring out which stages should be which, and what the seams look like.</p> <p>Most teams in 2026 are not running either. They are running a partial factory. Some stages are dark; CI runs unattended. Some stages are light; the merge to main requires a reviewer. The work is figuring out which stages should be which, and what the seams look like.</p>
<h2>What the marketing version gets wrong</h2> <h2>The five positions</h2>
<p>The marketing version: "AI writes the code, the pipeline ships the code, humans go home early." That is a fantasy. It assumes the spec is correct, the spec is complete, the spec captures every invariant the running system must preserve. None of those are true today. None of them will be true next year.</p> <p>Treating "dark" and "light" as a binary loses the part that matters. The positions, named:</p>
<p>The working version: the dark factory is not "AI replaces engineers." It is "the engineer's judgment gets encoded once, at the spec layer, and the pipeline carries it forward without re-interpretation." That is a much smaller claim. It is also the only claim that actually scales.</p>
<h2>The naming</h2>
<p>I borrow the term from manufacturing. A dark factory in the literal sense is a building with no lights on because no humans are inside; robots do the work. The analogy breaks in one place and one place only. In a physical dark factory, the parts are made of metal. In a software dark factory, the parts are made of <em>decisions</em>. And decisions are the one thing that does not transfer cleanly across a handoff.</p>
<p>That is the book. The next several posts are the load-bearing pieces.</p>
<h2>The spectrum, named</h2>
<p>Rather than treating "dark" and "light" as a binary, I find it useful to name five positions on the spectrum:</p>
<ol> <ol>
<li><strong>Manual</strong>. A person runs the commands. No factory yet; the engineer is the build system.</li> <li><strong>Manual.</strong> A person runs the commands. No factory yet; the engineer is the build system.</li>
<li><strong>Assisted</strong>. CI exists. Tests run. A person merges. Most teams in 2026 live here and call it "DevOps."</li> <li><strong>Assisted.</strong> CI exists. Tests run. A person merges. Most teams in 2026 live here and call it DevOps.</li>
<li><strong>Light</strong>. Merge is gated by policy, not by reviewer. The pipeline is the gate. A human is the auditor, not the approver.</li> <li><strong>Light.</strong> Merge is gated by policy, not by reviewer. The pipeline is the gate. A human is the auditor, not the approver.</li>
<li><strong>Dark, gated</strong>. The pipeline ships. A human is the only one who can promote from staging to production. The dark factory runs, but it cannot cross a particular seam without a key turn.</li> <li><strong>Dark, gated.</strong> The pipeline ships. A human is the only one who can promote from staging to production. The factory runs, but it cannot cross a particular seam without a key turn.</li>
<li><strong>Dark, full</strong>. The pipeline ships. Promotion is policy-driven. The human's role is to write the policy and the spec, then to inspect the artifacts the factory produces.</li> <li><strong>Dark, full.</strong> The pipeline ships. Promotion is policy-driven. The human's role is to write the policy and the spec, then to inspect the artifacts the factory produces.</li>
</ol> </ol>
<p>Most serious engineering organizations in 2026 are between three and four. The interesting question is not "how do we get to five" but "which of our stages should be at which position, and why."</p> <p>Most serious engineering organizations in 2026 sit between three and four. The interesting question is not how to get to five. The interesting question is which of your stages should be at which position, and why.</p>
<h2>Why the term matters</h2> <h2>What the framing changes</h2>
<p>Calling it a factory changes the questions you ask. You stop asking "who is on call for the deploy" and start asking "what is the failure mode of the deploy step." You stop asking "how fast can my engineers merge" and start asking "how fast can the policy express a correct merge." You stop asking "is the code reviewed" and start asking "is the spec from which the code was generated auditable."</p> <p>Calling it a factory reallocates where the engineering effort goes.</p>
<p>The factory framing is not a metaphor. It is a reallocation of where the engineering effort goes. A factory is designed, not grown. A factory is maintained, not improvised. A factory has a failure budget, not a heroism budget.</p> <p>You stop asking who is on call for the deploy and start asking what the failure mode of the deploy step is. You stop asking how fast your engineers can merge and start asking how fast the policy can express a correct merge. You stop asking whether the code was reviewed and start asking whether the spec the code was generated from is auditable.</p>
<p>If you have been calling a pile of bash scripts and a Slack channel "the build system," the factory framing will be uncomfortable. That is the point.</p> <p>A factory is designed, not grown. A factory is maintained, not improvised. A factory has a failure budget, not a heroism budget.</p>
<h2>What comes next</h2> <p>If the build system you are running today is a pile of bash scripts and a Slack channel, the factory framing is going to be uncomfortable. That is the point.</p>
<p>The next post in this series is <a href="/blog/light-vs-dark-factories">Light vs Dark Factories</a>; why most teams will end up in the middle, and why the middle is harder to run than either end.</p> <p>The next post in this series is <a href="/blog/light-vs-dark-factories">Light vs Dark Factories</a>.</p>
</div> </div>
</article> </article>
@ -105,13 +95,6 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
font-weight: 600; font-weight: 600;
} }
.post-content h1 {
font-family: var(--font-heading);
font-size: clamp(2rem, 4vw, 3rem);
color: var(--color-brown-dark);
margin: 0 0 1rem;
}
.lead-question { .lead-question {
font-size: 1.25rem; font-size: 1.25rem;
font-weight: 600; font-weight: 600;

View file

@ -1,150 +0,0 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
---
<BaseLayout
title="Where Dark Factories Are Already Running (and What to Learn From Them)"
description="The dark factory is not a thought experiment. Three of the largest companies in tech are running pieces of one. Here is what is working, what is breaking, and what the rest of us can learn."
ogType="article"
canonicalUrl="/blog/where-dark-factories-are-already-running"
pageType="blog"
>
<article class="post">
<header class="post-header">
<div class="post-meta">
<span class="post-date">July 16, 2026</span>
<span class="post-tag">AI</span>
</div>
<h1>Where Dark Factories Are Already Running (and What to Learn From Them)</h1>
</header>
<div class="post-content">
<p class="lead-question">Three companies are running pieces of a dark factory in production right now. None of them call it that. The vocabulary is missing, and the vocabulary is the part you need.</p>
<p>I spent the spring talking to platform teams at four companies that are visibly running some version of an unattended build pipeline. Three of them were willing to talk about it on background. The fourth one said no, and that is fine, because what they are doing is not what I want to write about anyway.</p>
<p>What I want to write about is the shape of what is actually working. The marketing version of "the dark factory" is a fantasy. The working version is a smaller claim, and the smaller claim is the one you can actually learn from.</p>
<h2>Company 1: a hyperscaler you have heard of</h2>
<p>This is the one that surprised me. I expected a small team with a clever pipeline. What I found was a 60-person platform org running a fully dark build pipeline for one of the company's internal product surfaces. The pipeline takes specs from a domain-specific tool the company built. The pipeline produces signed, attested artifacts. The pipeline ships them to a production cluster without a human in the loop.</p>
<p>The pipeline has been running for three years. The pipeline has had four outages. The first outage was caused by a bad spec. The second outage was caused by a spec that was good but a tool that was bad. The third outage was caused by a network policy that was too aggressive. The fourth outage was caused by a human, in the audit, pushing a button they should not have pushed.</p>
<p>The interesting detail: the policy operator is the only operator in the system that is written by hand. Everything else is generated. The policy operator is 4,000 lines of Go, and the engineer who wrote it said, "I will rewrite it next year. It is the part I am least proud of, and the part I most need."</p>
<h2>Company 2: a fintech that does not want to be named</h2>
<p>This is the company I thought would be running a dark factory. They are not. They are running a light factory with a dark middle. The spec-to-artifact step is fully unattended. The deploy-to-production step requires a human key turn. The key turn is the policy.</p>
<p>The reason is regulatory. The company has a regulator. The regulator wants a person to be the gate. The regulator does not care whether the person is right; the regulator cares that the person is the gate. The company designed the system around the regulator, not around the engineering ideal.</p>
<p>This is the most honest dark factory I have seen. The factory is shaped by the constraint, not by the marketing. The factory ships 50 times a day. The factory has a key turn. The key turn is the audit surface the regulator needs. The factory runs the way the business needs it to run, not the way the conference talk would have it run.</p>
<h2>Company 3: the agentic platform you are using</h2>
<p>This is the one most people will recognize, and the one I have written about before. A major agent platform is, in effect, running a dark factory for the prompts-to-actions translation layer. The user writes a prompt. The platform produces an action. The action is signed. The action is logged. The user did not approve the specific action; the user approved the prompt that led to the action.</p>
<p>The pattern is the same as a spec-to-artifact build pipeline. The prompt is the spec. The action is the artifact. The signature is the provenance. The platform is the factory. The user is the policy.</p>
<p>The interesting failure mode: the platform is good at the translation. The platform is bad at the policy. The user writes a prompt, and the platform produces an action, and the user has no audit surface to ask "what did the platform do, and why." The audit surface is the part nobody has built. The audit surface is the part that is going to define whether these platforms survive the next regulatory cycle.</p>
<h2>What the three have in common</h2>
<p>All three are running a version of the same shape:</p>
<ol>
<li><strong>A spec layer</strong>. The human writes the spec. The spec is the contract.</li>
<li><strong>A build layer</strong>. The build is fully dark. The build produces signed artifacts.</li>
<li><strong>A deploy layer</strong>. The deploy is dark, gated, or light, depending on the regulatory environment.</li>
<li><strong>A policy layer</strong>. The policy is the human's signature. The policy is the audit surface.</li>
<li><strong>An audit layer</strong>. The audit is a separate step. The audit is run by a different team than the build. The audit asks "did the policy work this week," not "is this artifact correct."</li>
</ol>
<p>None of them call it a "dark factory." All of them are running one. The vocabulary is missing. The vocabulary is the part that lets the rest of us talk about what is actually happening, instead of either pretending it is a marketing demo or pretending it is impossible.</p>
<h2>What the three get wrong</h2>
<p>All three are bad at the audit layer. The audit is treated as a separate concern. The audit is not integrated into the build. The audit is something the compliance team does, not something the factory does. This is a category error. The audit is a seam. The audit belongs to the factory, not to a different org chart.</p>
<p>The second thing they get wrong: the spec is treated as a documentation artifact, not as a code artifact. The spec lives in a wiki. The build lives in the cluster. When the spec changes, the build does not know until someone updates the build to read the new spec. The spec and the build are two systems. The spec and the build should be one system, with the spec as the source of truth and the build as the derived artifact. The provenance graph is the link.</p>
<h2>What you can do this quarter</h2>
<p>Pick one part of your pipeline that is currently gated by a human review. Pick the part that is the most boring, the most repeated, the least interesting. The one your senior engineer resents reviewing. Make that part dark.</p>
<p>Write down the spec. Make the spec a file. Make the file versioned. Make the build take the file. Make the artifact signed. Make the policy check the signature. Make the deploy gate on the policy. Watch what happens.</p>
<p>You will find two things. You will find that the part you made dark is faster and more reliable than it was. You will find that the human review you removed was catching a small number of real problems, and those problems now need a new home. The new home is the spec. Move the judgment from the review to the spec. Make the spec load-bearing. Make the build respect the spec. Make the policy enforce the spec.</p>
<p>That is the lever. That is the part you can do this quarter. The rest is scale.</p>
</div>
</article>
</BaseLayout>
<style>
.post {
max-width: 720px;
margin: 0 auto;
padding: 12rem 2rem 6rem;
}
.post-header {
margin-bottom: 3rem;
}
.post-meta {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
font-size: 0.875rem;
}
.post-date {
color: var(--color-text-muted);
}
.post-tag {
color: var(--color-amber);
font-weight: 600;
}
.lead-question {
font-size: 1.25rem;
font-weight: 600;
color: var(--color-brown-dark);
margin-bottom: 1.5rem;
line-height: 1.5;
}
.post-content h2 {
font-family: var(--font-heading);
font-size: 1.5rem;
color: var(--color-brown-dark);
margin: 2.5rem 0 1rem;
}
.post-content p {
line-height: 1.7;
margin-bottom: 1.25rem;
}
.post-content ol,
.post-content ul {
line-height: 1.7;
margin-bottom: 1.25rem;
padding-left: 1.5rem;
}
.post-content li {
margin-bottom: 0.5rem;
}
.post-content strong {
color: var(--color-brown-dark);
}
</style>

View file

@ -4,7 +4,7 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<BaseLayout <BaseLayout
title="Why Kubernetes for a Dark Factory" title="Why Kubernetes for a Dark Factory"
description="Kubernetes is the only widely-deployed substrate that gives a single engineer the same leverage a platform team gives a thousand. Here is why that matters for a dark factory, and why the alternatives do not hold up." description="A dark factory is a control loop. Kubernetes is the most boring control loop in production. That is the reason."
ogType="article" ogType="article"
canonicalUrl="/blog/why-kubernetes-for-dark-factory" canonicalUrl="/blog/why-kubernetes-for-dark-factory"
pageType="blog" pageType="blog"
@ -23,53 +23,43 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
<p class="lead-question">A dark factory is a control loop. Kubernetes is the most boring control loop in production. That is the reason.</p> <p class="lead-question">A dark factory is a control loop. Kubernetes is the most boring control loop in production. That is the reason.</p>
<p>I have built dark factories on Nomad. I have built them on bare systemd. I have built them on a single VM with a cron job and a Slack webhook. The smallest one ran on a Raspberry Pi in a closet in Texas for nine months without paging anyone. The largest one ran on a managed Kubernetes service and handled 400 deploys a day across four regions.</p> <h2>What the substrate has to do</h2>
<p>Of those, the Kubernetes one is the only one I would recommend to a single engineer in 2026. Here is why.</p> <p>A dark factory has four requirements from whatever it runs on.</p>
<h2>What a dark factory needs from its substrate</h2>
<p>A dark factory has four requirements from whatever it runs on:</p>
<ol> <ol>
<li><strong>Declarative desired state</strong>. The system has to be able to say "I want N copies of this artifact running, and the latest signed version, behind this network policy," and have the substrate reconcile to that state without the engineer babysitting.</li> <li><strong>Declarative desired state.</strong> The system has to be able to say "I want N copies of this artifact running, signed, behind this policy," and have the substrate reconcile to that state unattended.</li>
<li><strong>Restart and replace as a primitive</strong>. Failures are not exceptions. Failures are the steady state. The substrate has to make "kill it and start a new one" cheap, automatic, and observable.</li> <li><strong>Restart and replace as a primitive.</strong> Failures are the steady state. "Kill it and start a new one" has to be cheap, automatic, and observable.</li>
<li><strong>Operator-extensible control plane</strong>. The factory needs to add new resource types as it grows. It needs the substrate to treat those resource types as first-class, not as jobs squashed into the lowest common denominator.</li> <li><strong>An operator-extensible control plane.</strong> The factory grows new resource types as the system grows. The substrate has to treat those types as first-class, not as jobs squashed into the lowest common denominator.</li>
<li><strong>Boring upgrades</strong>. The factory runs unattended. The substrate upgrades cannot require a person to read release notes on a Saturday.</li> <li><strong>Boring upgrades.</strong> The factory runs unattended. The substrate cannot require a person to read release notes on a Saturday.</li>
</ol> </ol>
<p>Kubernetes is not special because it is fast, or because it scales, or because it is cloud-native. Kubernetes is special because it is the only widely-deployed substrate that makes all four of those requirements boring.</p> <p>Kubernetes is not special because it is fast, or because it scales, or because it is cloud-native. Kubernetes is special because it is the only widely-deployed substrate that makes all four of those requirements boring.</p>
<h2>Why the alternatives fall short</h2> <h2>Why the alternatives fall short</h2>
<p><strong>Serverless</strong> (Lambda, Cloud Functions, Workers) gets close on restart-and-replace. It fails on declarative desired state. The platform owns the loop, not you. The moment you need a custom resource type, the platform tells you no. The factory that wants to define a <code>BuildRun</code> resource cannot do it on Lambda.</p> <p><strong>Serverless</strong> (Lambda, Cloud Functions, Workers) gets close on restart-and-replace. It fails on declarative desired state. The platform owns the loop, not you. The moment you need a custom resource type, the platform tells you no. A factory that wants to define a <code>BuildRun</code> cannot do it on Lambda.</p>
<p><strong>Systemd on a VM</strong> gets close on boring upgrades. It fails on operator-extensible control plane. The minute you want a custom resource type, you are writing your own reconciler. You are now maintaining a control plane in addition to the factory. The single engineer does not have that time.</p> <p><strong>Systemd on a VM</strong> gets close on boring upgrades. It fails on the operator-extensible control plane. The minute you want a custom resource type, you are writing your own reconciler. You are now maintaining a control plane in addition to the factory. The single engineer does not have that time.</p>
<p><strong>Nomad</strong> is the most underrated of the three. Nomad is what Kubernetes would look like if HashiCorp had cared more about operator patterns and less about service mesh. Nomad is excellent. Nomad is also a single-vendor system, and the ecosystem of pre-built operators and CRDs does not exist. You will build everything from scratch.</p> <p><strong>Nomad</strong> is the most underrated of the three. Nomad is what Kubernetes would look like if HashiCorp had cared more about operator patterns and less about service mesh. Nomad is excellent. Nomad is also a single-vendor system, and the ecosystem of pre-built operators and CRDs does not exist. You will build everything from scratch.</p>
<p><strong>Docker Compose on a single host</strong> works until the host dies. Then the dark factory is dark in a different sense; the lights are off, the artifact is gone, and you find out what your backup posture actually is.</p> <p><strong>Docker Compose on a single host</strong> works until the host dies. Then the dark factory is dark in a different sense. The lights are off. The artifact is gone. You find out what your backup posture actually is.</p>
<h2>The single-engineer argument</h2> <h2>The single-engineer argument</h2>
<p>The argument I want to make is the leverage one. Kubernetes is the only substrate that gives a single engineer the same leverage a 20-person platform team gives a thousand. That leverage comes from the operator pattern.</p> <p>An operator is a reconciler. The operator watches a custom resource. The operator makes the cluster match the resource. The operator is written in Go and packaged as a container. The operator runs the same way the artifact runs. The operator is part of the factory.</p>
<p>An operator is a reconciler. The operator watches a custom resource. The operator makes the cluster match the resource. The operator is written in Go (mostly) and packaged as a container. The operator runs the same way the artifact runs. The operator is part of the factory.</p> <p>A platform team of 20 cannot build a custom resource type faster than a single engineer with an operator template. The single engineer's bottleneck is the spec, not the infrastructure. The infrastructure is the easy part. The hard part is figuring out what the factory should do, and that is the same problem at any team size.</p>
<p>A platform team of 20 cannot build a custom resource type faster than a single engineer with an operator template. The single engineer's bottleneck is the spec, not the infrastructure. The infrastructure is the easy part. The hard part is figuring out what the factory should do, and that is the same problem in both cases.</p>
<h2>What Kubernetes does not give you</h2> <h2>What Kubernetes does not give you</h2>
<p>Kubernetes does not give you a factory. Kubernetes gives you a substrate on which a factory can be built. The gap between "I have a cluster" and "I have a factory" is roughly the size of the next post in this series; the operator pattern.</p> <p>Kubernetes does not give you a factory. Kubernetes gives you a substrate on which a factory can be built. The gap between "I have a cluster" and "I have a factory" is the size of the next post in this series: the operator pattern.</p>
<p>Kubernetes also does not give you provenance. The cluster will run whatever artifact you give it. The cluster does not know where the artifact came from. The cluster does not know whether the artifact was generated from a spec, or by a human, or by a model with no spec. The cluster does not care. Provenance is a layer above the substrate, and the layer above Kubernetes is where the dark factory actually lives.</p> <p>Kubernetes also does not give you provenance. The cluster will run whatever artifact you give it. The cluster does not know where the artifact came from. The cluster does not know whether the artifact was generated from a spec, or by a human, or by a model with no spec. The cluster does not care. Provenance is a layer above the substrate, and that is where the dark factory actually lives.</p>
<h2>The choice</h2>
<p>If you are a single engineer in 2026 trying to build a dark factory, the choice of substrate is not really a choice. Kubernetes is the answer. The interesting work is what you build on top of it.</p> <p>If you are a single engineer in 2026 trying to build a dark factory, the choice of substrate is not really a choice. Kubernetes is the answer. The interesting work is what you build on top of it.</p>
<p>If you are a platform team of 20, the choice is also Kubernetes, but the leverage argument is reversed. The platform team has the leverage to consider Nomad, or a managed control plane, or a custom substrate. The single engineer does not. The single engineer needs to be the platform team's customer, not the platform team's peer.</p>
</div> </div>
</article> </article>