The org chart should compile
At first I was concerned about the phrase “the org chart should compile,” because that is not quite what I originally said.
But I think it is the goal.
I think we’re all collectively working on solving the “enterprise architect who can’t keep up with code, so gives up and retreats” problem.
My solution is that everyone in the management chain personally maintains code. One manager, one class file.
The CEO does not directly own every implementation line. But they indirectly own its contract: production code must map back to the model they are accountable for. Their file represents what is in their head—how they imagine the company and its systems currently work—and lets them pull up the people and code responsible for making that model true.
That file replaces the phone tool. Instead of listing reports as names, it imports their models. Instead of stopping at an org chart, those models link into the actual services, data stores, metrics, policies, and billing systems below them. From ceo.ts, you should be able to enter the whole company.
The idea in three files
ceo.ts
export class CeoModel {
company = {
product: engineering.system,
trust: security.expectations,
money: finance.expectations
}
}
export const ceo = new CeoModel()
import { engineering } from "./engineering-manager"
import { finance } from "./finance-manager"
import { security } from "./security-manager"
engineering-manager.ts
export class EngineeringManagerModel {
datastore = new ExpectedUserStore()
backend = new BackendService(this.datastore)
system = {
frontend,
backend: this.backend,
datastore: this.datastore,
metrics
}
}
export const engineering = new EngineeringManagerModel()
import { BackendService } from "./backend-service"
import { ExpectedUserStore } from "./expected-user-store"
import { frontend, metrics } from "./system"
backend-service.ts
export class BackendService {
constructor(private users: UserStore) {}
upgradeUser(userId: string, plan: Plan) {
const user = this.users.find(userId)
const upgraded = { ...user, plan }
this.users.save(upgraded)
return upgraded
}
}
import type { Plan, UserStore } from "./user-store"
The CEO model does not stand up a REST service or a database. It enters the engineering manager’s model, which imports the real BackendService class but supplies a small store representing how the manager believes user data behaves.
The REST endpoint, network serialization, AWS credentials, and database startup are not part of the CEO’s mental model, so they are not required to run it. The domain service is.
That makes the model executable. It also means the CEO can attach expectations to it.
The model connected to production code
ceo.ts
export class CeoModel {
company = {
product: engineering.system,
trust: security.expectations,
money: finance.expectations
}
}
export const ceo = new CeoModel()
import { engineering } from "./engineering-manager"
import { finance } from "./finance-manager"
import { security } from "./security-manager"
ceo.expectations.test.ts
describe("the company in the CEO's head", () => {
it("upgrades a customer without exposing their data", () => {
const customer = ceo.company.product.backend
.upgradeUser("vanja", "pro")
expect(customer.plan).toBe("pro")
expect(ceo.company.product.datastore.find("vanja").plan).toBe("pro")
expect(ceo.company.money.canBill("pro")).toBe(true)
expect(ceo.company.trust.humansCanReadUserData).toBe(false)
})
})
import { ceo } from "./ceo"
engineering-manager.ts
export class EngineeringManagerModel {
reports = [backendDeveloper, dataDeveloper]
datastore = new ExpectedUserStore()
backend = new BackendService(this.datastore)
system = {
backend: this.backend,
datastore: this.datastore,
metrics
}
}
export const engineering = new EngineeringManagerModel()
import { BackendService } from "./backend-service"
import { backendDeveloper } from "./backend-developer"
import { dataDeveloper } from "./data-developer"
import { ExpectedUserStore } from "./expected-user-store"
import { metrics } from "./system"
backend-service.ts
export class BackendService {
constructor(private users: UserStore) {}
upgradeUser(userId: string, plan: Plan) {
const user = this.users.find(userId)
const upgraded = { ...user, plan }
this.users.save(upgraded)
return upgraded
}
}
import type { Plan, UserStore } from "./user-store"
user-store.ts
export interface UserStore {
find(userId: string): User
save(user: User): void
}
export type Plan = "free" | "pro"
export type User = {
userId: string
plan: Plan
}
expected-user-store.ts
export class ExpectedUserStore implements UserStore {
private users = new Map([
["vanja", { userId: "vanja", plan: "free" as Plan }]
])
find(userId: string) {
return this.users.get(userId)!
}
save(user: User) {
this.users.set(user.userId, user)
}
}
import type { Plan, User, UserStore } from "./user-store"
production-user-store.ts
export class ProductionUserStore implements UserStore {
find(userId: string) {
return usersTable.get({ userId })
}
save(user: User) {
usersTable.put(user)
}
}
import { usersTable } from "./aws-production-account"
import type { User, UserStore } from "./user-store"
rest-api.ts
const users = new ProductionUserStore()
const backend = new BackendService(users)
router.post("/users/:userId/plan", request => {
return backend.upgradeUser(
request.params.userId,
request.body.plan
)
})
import { BackendService } from "./backend-service"
import { ProductionUserStore } from "./production-user-store"
import { router } from "./web"
The CEO’s model and the REST API use the same production BackendService. The CEO’s model circumvents the REST layer and substitutes ExpectedUserStore for the literal production database. It is not a fake version of the business behaviour. It is the CEO’s version of the boundaries that do and do not matter.
Now the CEO’s expectations can run continuously. If an engineer changes BackendService and the CEO’s test breaks, one of two useful things has happened: the implementation violated an expectation, or the CEO’s understanding of the system is no longer true. Either the production change is wrong, or the mental model needs to be updated.
That is what I mean by the org chart compiling. The company becomes one giant system where people can attach their expectations at the level they think. Engineers have implementation tests. Managers have service and data-flow expectations. The CEO has company-level expectations. Each layer links down into as much real code as it needs and replaces the irrelevant infrastructure with a representative boundary.
AI makes maintaining these models cheap. It can translate a manager’s explanation into code, trace the imported production classes, run the expectations, and show exactly where two models stopped agreeing. The human still owns the expectation. AI keeps it connected.
Non-manager engineers work in a shared space. My condolences to them.
In this model, AI slop is indistinguishable from human slop. It either preserves the expectations people have attached to the company, or it breaks the graph.
Goals of this system
I have not solved how name.ts should connect to service-name.ts. A direct import is the simplest demo, but it may not be the right protocol. The connection could be generated from ownership metadata, resolved through interfaces, or maintained as a tested mapping. The goal is that a person can move from a manager’s expectation to the responsible service and its human owner without searching the company by folklore.
The system should also allow someone to make a claim at any depth. If a CEO claims to understand a process ten layers down the stack, that claim should become an expectation they own. They do not suddenly own all ten layers of implementation, but they do own the assertion that a particular result must survive them.
That is the useful version of indirect code ownership. A manager can pull up the code supporting their model. If it changes incompatibly, their expectations fail. They then have to decide whether the implementation is wrong or their understanding needs to change.
The strongest version would let a lead architect point at one part of the company and say:
Yes, this part must work like this. Figure out the rest.
That sentence becomes a live test. Everyone below it remains free to change transports, databases, services, team boundaries, and implementation details, as long as the promised behaviour survives.