Gravity
The distributed monolith has a specific moment of discovery.
Not when someone announces the new architecture. Not when the first service goes live and everyone feels the clarity of separation: this team owns authentication, that team owns payments, different repositories, different deploys, real autonomy at last. The moment comes later. It comes at 2am during a production incident, when a developer realizes that fixing Service C requires understanding the current state of Services A, B, and F, and that none of those services expose their state in a way that makes this tractable, and that the only person who knows how they’re coupled is in a different timezone and offline.
The team broke the monolith to gain autonomy. They got eight services they don’t understand instead of one.
The microservices revolution was partly technical and partly organizational. Separate services could be deployed independently, could fail without taking down the whole system, could scale differently depending on load. Teams could own their boundaries.
The services were genuinely autonomous. The isolation was not.
Service A called Service B. Service B depended on Service C. Service C read from a database that Services A, D, and E also read from. So: a service mesh to manage the dependencies. Centralized observability to monitor service health. An orchestration layer for workflows spanning multiple services. By the time this settled, there was a single system coordinating and controlling all the autonomous services. A center. Different from the original monolith, but a center.
The services didn’t escape centralization. They distributed its implementation across more machines while rebuilding its logic under a different name.
Each constraint is a wire back to the center.
You delegate because the delegated party has local context you don’t. That’s the whole point. But you still need to know if the delegation is working. So you add monitoring. And you don’t want the delegated party to do anything catastrophic. So you add constraints. Rules about what the component can and can’t do. Approval requirements above certain thresholds. Kill switches for emergencies. “You can do X but not Y” is a statement from the center about what the autonomous component is allowed to decide. Add enough of those statements and the autonomous component is executing pre-approved decisions with extra steps.
The question “but what if it does X?” always gets answered with a safeguard. The safeguard is always a wire. Pull enough wires and you can feel the tension from across the room. It has a direction. It points back.
I was building a system that was supposed to think.
The plan: Metatron, the news-gathering pipeline, would produce data. Cortex, the reasoning layer, would have context, memory, goals, and the ability to decide what to do with that data. The system would act, not just report.
The first version of the decision layer had a kill switch. DECISION_LAYER_ENABLED=false in the environment. Reasonable: new system, don’t trust it yet.
Then a priority system. Seven levels, P1 through P7. Cortex evaluates incoming signals against priority. High-priority events trigger action. Lower-priority events might not. Also reasonable: not every signal deserves a response.
Then a tier system for actions. Tier 1: autonomous. Tier 2: self-review before acting. Tier 3: ask for approval before anything.
I listed what lived in Tier 1 and sat with it for a moment. Posting low-stakes Slack messages. Storing memories. Running health checks. Things nobody would question because there was nothing to question: no stakes, no judgment, no way to be wrong in a way that mattered.
Tier 3 covered everything else. Anything with external impact. Anything that could be wrong.
I’d built the distributed monolith. The center was just me.
Here is the moment I keep circling. A news signal came in about a policy change that would affect people the person I built this around cares about. Cortex evaluated it. High priority, high relevance, clear connection to active goals. If I’d been looking at it myself, I would have drafted something and sent it to Slack within minutes. That’s what the system was built to do.
But Cortex would have drafted it differently. Not wrong. I couldn’t point to a factual error or a misjudgment. Just a different emphasis, a different framing, a different read of what mattered most in the signal. The kind of difference you’d get from any two people reading the same article. And I realized I was not willing to have that message appear in a channel under my name with phrasing I hadn’t chosen.
That was Tier 3. Not because the action was dangerous. Because the action was visible and the voice wasn’t mine.
What I kept returning to was: what exactly was I protecting against? Not malfunction. The tier system wasn’t primarily about Cortex breaking. It was about Cortex deciding. The decisions that required trusting Cortex lived in Tier 3 because I wasn’t ready to accept a decision I wouldn’t have made. Not wrong. Different. Different enough that, asked beforehand, I would have said no. The tier system is what that limit looks like when you compile it into code.
The honest word for what I built is control.
Real delegation means the delegated component sometimes makes decisions you wouldn’t have made. You accepted them because you accepted the delegation.
The problem is calling it delegation when it isn’t. The word shapes what you optimize for. Call it delegation and you’ll keep trying to extend trust, remove guardrails, grant more autonomy. Call it controlled automation and you optimize honestly: clear scope, explicit approval chains, known limits. The honest version is more useful to build.
I don’t know if real delegation is possible for high-stakes decisions in complex systems. I know what it would require: accepting that something will happen without your approval, and not treating that as a failure condition. Every time that’s unacceptable, the wire gets rebuilt.
The kill switch is still in the environment. I haven’t changed it to true.