Spec0
All posts
Ownership 8 min read

API ownership belongs to teams, not people

Ownership pinned to a person is a fact with an expiry date. The first reorg, the first resignation, and the record of who owns what is quietly wrong.

It is two in the morning and the payments API is misbehaving. You do the thing you are supposed to do: you find the owner. The record is clear enough. It says the API is owned by jsmith. You page jsmith. Nothing comes back, because jsmith moved to the data team a year ago and left the company in the spring. The API is very much alive, serving traffic, paging you, and according to every record you can find it belongs to a person who is gone.

So the archaeology begins. You check the repository history, which points at jsmith and two contractors. You ask in a channel, at two in the morning, and wait. Eventually someone who has been around long enough remembers that payments got absorbed into the billing team during the last reorg, and that a person there probably knows. The API was never orphaned in production. It was orphaned in the records, which is worse, because the records were the thing you were supposed to be able to trust.

Nobody updated the owner when jsmith left, because updating it was nobody’s job. It was jsmith’s, and jsmith is gone.

A durable thing pinned to a volatile one

The structural problem is that ownership got attached to the most volatile entity in the organisation.

Ownership lands on individuals because individuals are who did the work, and writing down a name is the natural thing to do. I built this, so the record says I own it. That feels correct on the day it is written and is wrong within a year, because the API and the person have completely different lifespans. The API persists. It will outlive the tenure of whoever wrote it, usually by years, often by a reorg or two. The person is the least permanent thing in the building: they change teams, get promoted, take leave, resign. Pinning something durable to something that moves guarantees the record goes stale, and it goes stale silently, because a person changing teams does not trigger a sweep of every ownership record with their name on it.

So the decay is not an accident that better discipline would fix. It is the predictable result of choosing the wrong noun. A name is a snapshot of who happened to own something on the day someone wrote it down.

sequenceDiagram
    participant REC as Ownership record
    participant API as payments API
    participant YOU as You, at 2am
    REC->>REC: owner = jsmith (wrote it in 2024)
    Note over REC: jsmith changed teams, then left
    API->>YOU: incident, right now
    YOU->>REC: who owns payments?
    REC-->>YOU: jsmith, a ghost
    Note over YOU: page nobody, then start asking around

The tax on whoever needs an owner

Day to day, the cost is that the ownership field cannot be trusted, so people stop using it.

Every time you need an owner and there is a real chance the record points at someone who has moved on, you learn to route around it. You do not page the name; you ask a human who has been here a while. Which means ownership has quietly reverted to tribal knowledge, the exact thing the record existed to replace. The field is still there, still filled in, still wrong often enough that nobody relies on it, which is the worst state for a record to be in: present enough to look authoritative, wrong enough to mislead.

The sharp version of this is on-call. Escalation policies encoded around individuals send the page to the person who left, at the moment you least want to be doing detective work. The incident does not care that the org chart moved. It just needs the owner, and the owner is a name that no longer maps to anyone.

The tax on the people who answer for the estate

Step back, and the same fragility undermines everything an organisation tries to build on top of ownership.

Reorgs are not rare events; they are the normal weather of any company past a certain size. Teams merge, split, get renamed, change managers. Every one of those quietly invalidates a swath of ownership records, because the records were tied to people and the people just got rearranged. You cannot run governance on that. “Every API must have an owner” is a hollow rule if half the owners are ghosts. You cannot route incidents, plan capacity, or answer “who is accountable for this” when the accountability layer decays every quarter.

And it makes onboarding and audit run on sand. A new engineering leader trying to understand what their group is responsible for gets a map drawn in names, many of which no longer mean anything, and the only way to correct it is to ask the longest-tenured person in the room, which is to say the map lives in a head, not a record.

The mismatch is structural, not sloppy

You do not need a survey to see the shape. An organisation of any size reorganises on the order of once a year, and a meaningful fraction of people change teams or leave in that time. Each of those moves silently ages the ownership records attached to that person. Meanwhile the APIs sit still, outliving the people by years.

So the rate at which person-pinned ownership decays is set by how often people move, and the length of time it needs to stay correct is set by how long the API lives. Those two numbers are wildly mismatched, and no amount of diligence closes the gap, because the diligence required is “update every record every time anyone moves”, which is precisely the kind of manual synchronisation that never happens.

Why the usual records rot

The tools we use to record ownership mostly encode the person, which is why they decay.

CODEOWNERS is the reflex, and it can point at a team, but in practice it is littered with individual handles, and when it names a person it rots the moment they move. It is also scoped to a repository, not to an API or an operation, so it answers “who reviews this code” rather than “who owns this contract”, and it says nothing about the ownership of anything that is not a file in that repo.

Service catalogues can attach an owner to a group, which is the right instinct, but the field is hand-maintained and nothing enforces that it names a team rather than a person, so the discipline erodes and the catalogue drifts to whatever someone typed once.

git blame and the last-committer heuristic are the tempting shortcut, and they are a trap. They tell you who touched the file last, which might be a contractor, a drive-by fix, or an automated bump. Last to touch is not the same as accountable for, and treating them as equal is how you page the wrong person with confidence.

None of these make the durable unit the owner and keep its membership current as a fact about the organisation.

What would have to be true

Argue it from the properties.

Ownership has to attach to a team, not an individual, because the team is the stable noun. It is the thing that outlives any single member, the unit the organisation already reasons in, and the level at which accountability actually sits. A person is a poor primitive for a durable fact.

The team’s membership has to be maintained as an organisational fact, so that “who is responsible for this API” resolves through the team’s current roster rather than a name frozen in a file. People joining and leaving the team is the event that updates the answer, and it updates it everywhere at once, because the answer was never a name in the first place.

Ownership has to survive a reorg. When a team is renamed, merged or absorbed, ownership should follow the team as an entity, not shatter into a list of individuals who have to be re-assigned by hand.

And it has to be the single thing everything else resolves against: governance, incident routing, change notifications, the lot. One owner of record, at the level of the team, so there is exactly one answer and it is current.

graph LR
    API["payments API"] -->|owned by| TEAM["Billing team"]
    TEAM -->|current roster| NOW["whoever is on the team now"]
    LEAVE["jsmith leaves"] -->|updates the roster, not the owner| NOW

How we come at it

Full disclosure: this is the spec0 blog, and team-based ownership is a load-bearing choice in how we are built, so read this as interested rather than neutral.

spec0 is organised around teams and the specs they own. Ownership is attached to the team as an entity, precisely because it has to survive the reorg: a person leaving does not orphan an API, because the API was never owned by that person. The team still owns it, and who to actually talk to resolves through the team’s current membership rather than a name someone wrote down two years ago. Governance, ownership questions and routing all resolve against the team, so there is one answer and it moves when the team does, not when someone remembers to edit a file.

The honest limit is that this models teams and their ownership; it does not run your HR system. Keeping team membership current is still organisational hygiene. What it removes is the specific failure of an API whose owner is a person who is gone, by never encoding the person as the owner in the first place.

The part worth arguing about

Teams are more stable than people, but they are not permanent. Teams get dissolved, merged and renamed too, so pinning ownership to a team pushes the volatility up a level rather than removing it. It is a much better level, because teams move far less often than people and their membership is a fact the organisation already tracks, but the problem does not vanish; it just gets rarer and larger. When a team is dissolved, its APIs need re-homing, and the question of who notices, and who decides where they go, is real.

So the thing I keep turning over is whether there is a stable-enough unit above the team, a domain or a capability that outlives even the teams inside it, or whether periodic re-homing is simply the cost of an organisation that keeps changing shape. If you have found a unit of ownership that survived several reorgs without a manual clean-up each time, I would like to know what it was, and whether it held because of the unit or because someone quietly kept it honest.