Gates, Not Micromanagement
Primer
Control lives on the transitions; between them nobody watches. ๐ Hi, I'm Anton - a software engineer working mostly in PHP/Symfony and Go, currently carving a live PHP monolith into Go services. This series is about the order the work happens in: a wish becomes requirements, requirements become a contract, the contract becomes tasks and specs. This part is about where the checks sit on that road, and about the kind of supervision I stopped doing. Running notes live on my GitHub: github.com/brilliant-almazov. This is how I do it right now, with the price attached - maybe you already do it better, maybe you see it differently.
The shape of the work in this series: a wish becomes requirements, requirements become a contract declared in a schema, the contract becomes tasks, and a task becomes a spec - a self-contained brief that one executor runs end to end without reading anything outside the files it names. An executor is whoever performs one such spec; here that is usually an automated one, and nothing below changes if it is a person. A lead prepares the facts, hands the specs out and accepts the results. That is the whole cast: a road with steps on it, specs travelling down it, and one person deciding whether a step has been passed.
The Thesis
Control belongs on the transitions, not on the process. Watching how the work is going produces no fact that the acceptance of the next transition would not produce anyway. It produces a feeling of proximity, at the price of an interruption on both sides - and it produces it repeatedly, because a process has no natural end and a transition does.
So the road from a wish to a release is cut into five transitions, and each of them carries exactly two things: what is accepted, and what proves it. Everything between two gates is nobody's business until the next gate.
wish ──โถ requirements ──โถ contract ──โถ spec ──โถ execution ──โถ acceptance ──โถ release
│ │ │ │ │ │
[1] [2] [3] [4] [5]
numbers compatibility no open one command build, tests,
question that runs not "fast" is green
How This Is Normally Done
Nothing below is a criticism. It is the baseline I moved away from, and every line of it is reasonable in the setting it came from.
| Practice | The common shape |
|---|---|
| Daily status | A daily meeting where everyone says what they did and what they will do |
| Board with columns | A work-in-progress limit on a board, so load is visible at a glance |
| Review along the way | Reading changes as they appear, not only at the end |
| Progress report | A written summary of how far along the work is, produced on a cadence |
All four answer the question how is it going. None of them answers may this step be passed. That is the question I care about, because it is the only one that changes what happens next.
The Five Gates
| Transition | What is accepted | What proves it |
|---|---|---|
| requirements → contract | requirements are complete and consistent | non-functional ones stated as numbers, not as the word "fast" |
| contract → spec | the contract is accepted | the compatibility check is green |
| spec → execution | the spec is runnable without reconnaissance | there is no open question in its text |
| execution → acceptance | the code does what it claims | one acceptance command |
| acceptance → release | the change does not break the neighbours | build, tests, structure and drift checks |
The third column is the whole design. It is not a wish, not a definition of done written in adjectives, not "the reviewer is happy". It is something that can be run or read: a number, a green check, the absence of a question mark, a command, a build. A gate whose third column cannot be filled in is not a gate. It is a meeting.
Firing One Looks Like This
execution ──โถ acceptance
────────────────────────────────────────────────
the claim: "the iteration is finished"
the artefact: one command, run, output read
────────────────────────────────────────────────
ok → transition passed
not ok → not accepted, no discussion of effort
The claim and the artefact are on separate lines on purpose. The first one is never the input to the decision; the second one always is.
Between the Gates, Nobody Watches
gate 3 ───────────────── the interval ───────────────── gate 4
spec handed over
nobody watches in here
acceptance ✗
no status check-in ✗
no progress report ✗
no review mid-run
Two consequences, and the second one is the uncomfortable one. Nobody interrupts the work in progress. Not to ask how it is going, not to suggest a better approach halfway, not to look at a half-written file. The interval belongs to whoever is inside it.
Responsibility is delegated together with the decisions. Whoever holds a gate has the right to say not accepted, and is not obliged to justify it line by line. That right is what makes the gate a gate; without it the gate degenerates into an opinion that can be argued past, and the process reverts to supervision by whoever argues longest.
A Gate Stands on an Artefact, Not on a Claim
This is the line I would keep if I had to delete everything else in this article. A statement that the work is done is not evidence that the work is done. Not from an executor, not from me. Every gate leans on an artefact - a number, a run, a file - and the artefact is looked at, not reported on.
The reason is not ideological, it is a property of the executor. Executors fail in a predictable, small set of ways, and the reliable answer to a predictable failure is an external check rather than trust. The ladder I use everywhere is:
- reminder - lives in one conversation
- rule - works for as long as somebody reads it
- check - works whether or not anyone remembers it exists
That ladder applies to me as much as to anyone else. When I say the spec is ready, that is a claim. When the spec contains no open question, that is a fact somebody can verify without me.
The Case: Five Signs, All Read at a Gate
Here is what this actually looks like on real work, rather than as a principle. A set of specs is written, handed out, executed, accepted. Along the way, five things can happen. Each of them is visible at a gate - during acceptance, or as a blocked write - and none of them requires anybody to have watched the work happen.
| Sign | What it actually means |
|---|---|
| a clarifying question was asked | a fact was not written into the spec |
| a rule blocked the write | a primitive that should have been reused was not named |
| two iterations edit the same file | the split into iterations is wrong |
| an iteration is rewritten after acceptance | the acceptance criterion was not checkable |
| an iteration ate more context than its named files need | a defect of the spec |
Read the right-hand column again. Not one entry says anything about the executor. Every one of them is a defect of the specification, discovered at a transition and paid for at that transition.
The extreme case of the last row is the number I keep coming back to in this series: iterations of one early set were eating about 350 000 tokens each, because the executor was assembling its own context - hunting for types, paths and signatures instead of receiving them. The tasks were completing. Nothing looked wrong from the outside. The cost was visible only because acceptance recorded it, and it turned into two concrete repairs - a closed list of files per iteration, and a section of stated facts in the controlling spec.
I am not going to attach a count of how often each sign fired, or how long a transition takes. Those numbers do not exist in my records, and inventing them next to a real one is how a real one stops being believed.
What It Looks Like from the Lead's Side
The chain is short, and the shape of it is the point:
- Prepare the facts. The only step where reading around the codebase is allowed at all.
- Hand out. One executor, one task, one context.
- Accept the iteration - by its own package only. There is no full run inside an iteration.
- Accept the stage - one full run, once, at the end.
The lead does not write code. That is not a rank, it is a conflict of interest: the person holding a gate should not also be the person whose work the gate is judging.
Why Gates and Not Observation?
Observation requires presence. A gate does not: it fires when the transition is attempted, whether or not anyone is at their desk. Observation catches only what has already happened, and usually catches it in the version the observer was told about. A gate catches a divergence at the moment of the transition, and it costs one run.
Observation scales badly. Two parallel executors are already more than one person can watch honestly; the gates do not care how many there are, because they sit on the road rather than on the worker.
What This Costs
Every gate needs an artefact, and building the artefact is work. A gate without one drifts into taste, and taste is exactly the thing being replaced. That is a real up-front bill: the compatibility check, the acceptance command, the structure and drift checks all had to be built before any of this could be run this way.
"Not accepted" without a line-by-line justification reads as rude. It works only where there is enough trust in whoever holds the gate, and it takes a while to establish that trust. In a setting without it, this style is corrosive.
Between gates, nothing is known about the work. If a transition is long, bad news arrives late. The cure is a finer split - more, smaller transitions - not the reintroduction of supervision. Every time I have been tempted to add a check-in, the real problem was that an iteration was too big.
When Not to Do This
- Research. When the transition is not visible yet, there is nothing to put a gate on. First the exploration, then the spec, then the gates.
- A task without a readiness criterion. "Make it nicer", "improve it" - there is nothing to accept, so acceptance cannot happen and the gate is theatre.
- Teaching someone new. Here the process itself is the point: watching how a person arrives at an answer is the entire content of the exercise. Gating only the outcome teaches nothing.
The Multiplier
An executor cannot be given a conversation about how the work is going. There is nowhere to put one. It can be given exactly two things: an input and a criterion - and it will return exactly what those two describe, including everything they failed to describe.
Which means the discipline that reads as harsh when applied to people turns out to be the only shape that works at all here. Not because the tooling demands rigour, but because it removes the fallback: with a person, a vague spec is quietly repaired by a conversation nobody records. With an executor there is no conversation, so the vagueness is delivered intact, in the output, at the gate. That is a good thing. It just leaves the definitions with nowhere to hide, and the definitions are still mine to get right.
Next
From requirement to contract - Part 4. Next: responsibility does not move to the executor, even when the executor writes most of the code - what stays on a person, and what it takes to keep it there.
If you do this better, tell me what your third column looks like - what artefact your transitions actually lean on. If you have been through this, what did removing the status check-in break first? If you see it differently, say where watching the process caught something a gate would have missed. How is it solved on your side, and what broke there?
Comments
No comments yet. Start the discussion.