There is a version of a software project that looks complete and is not. The features work, the tests pass, the client has signed off, and the system is running in production — and yet the only people who can safely change it are the people who built it. Everything needed to operate it exists, but it exists in the heads of three engineers and in a sequence of commands that one of them runs from memory. That project has delivered software and has not delivered a system.
The distinction matters commercially, not just ethically. A system that cannot be handed over has a permanent dependency attached to it, and that dependency has a price that nobody agreed to.
- The client cannot get a competitive quote for the next phase.
- They cannot bring the work in-house.
- They cannot replace the supplier without a discovery project first.
We would rather not be that supplier, partly because it is a bad deal for the client and partly because it makes our own work harder to staff.
A folder of documents is not a handover
The usual artefact at the end of a project is a documentation folder, and it is usually worthless within four months. Not because it was badly written, but because prose describing a system is a copy of the truth rather than the truth, and copies drift. The deployment document says to run three commands; a fourth was added in March and nobody updated the document, so the next person follows it, it fails on step three, and they stop trusting any of it.
The test of any handover artefact is therefore whether it breaks when it becomes wrong. A document does not break; it just quietly stops being true. A script breaks. A test breaks. A CI pipeline breaks loudly and in front of everyone. So the overwhelming majority of what we consider handover material is executable rather than written, and the written part is reserved for the one thing code cannot carry, which is why a decision was made.
This reframes the whole deliverable. Instead of asking what should be documented, you ask what should be automated, and the answer is: everything that would otherwise be a numbered list of instructions. Setting up a development environment, running the tests, deploying, rolling back, restoring a backup, rotating a credential, adding a new user — each of those is a script with a name, and the script is both the instruction and the proof that the instruction still works.
The first morning test
Our working definition of a finished handover is a single measurable claim: a competent engineer, with no prior exposure to the project, can clone the repository and have the system running locally with realistic data inside one morning, using only what is in the repository. Not a senior specialist, and not with somebody on a call — on their own, reading what is there.
This is a test rather than an aspiration, which means somebody has to actually run it. We do, with an engineer from a different project who has not seen the code, and we time it. The first attempt has never passed. It always surfaces three or four things that the team had stopped seeing: an environment variable that is only in somebody’s shell, a database extension installed by hand a year ago, a seed script that depends on a file in a bucket nobody mentioned.
Those are exactly the items that make a handover fail six months later, and they are invisible from inside the team because everybody’s machine already has them. The only reliable way to find them is to put the project in front of somebody whose machine does not, and the cost of doing that is one engineer for one morning against the cost of the alternative, which is a client discovering them during an emergency.
Realistic data, not an empty database
The clause about realistic data carries more weight than it looks. A system running against an empty database does not exercise anything interesting, and a developer who has only ever seen it empty cannot tell whether a change is correct. The seed script therefore has to produce a plausible organisation with a plausible history — enough records that pagination appears, enough variety that the edge cases exist, and no real customer information anywhere in it.
Deployment is part of the system
A system you cannot deploy is not handed over, whatever the code looks like. That means the deployment lives in the repository as a pipeline rather than in a person’s habits, and it means the pipeline is the only way anything reaches production — including for us, including during an incident, because a deployment path that is bypassed under pressure is a deployment path that is not tested when it matters.
The rollback is the half that gets skipped. Deploying forward is the exciting direction and it is the one that gets rehearsed; going back is the direction you need at two in the morning with somebody senior on the phone. So the rollback is a documented, scripted, rehearsed operation with a known duration, and the handover includes having watched the client’s own team perform it once on a non-critical change.
Credentials belong in the same category. A system where only the supplier can rotate a secret is a system the client does not control, and the correct arrangement is that every credential is held somewhere the client owns, with a written procedure for rotating each one and a record of when each was last rotated. We have handed over systems where performing that rotation together was the final session, because it is the one operation that proves ownership has actually transferred.
| Operation | Handed over as | Proven by |
|---|---|---|
| Run it locally | One command plus a seed script | A new engineer doing it unaided |
| Deploy | A pipeline in the repository | The client’s team releasing once |
| Roll back | A scripted, timed procedure | A rehearsal on a real change |
| Rotate a secret | A written per-credential procedure | Doing it together, once |
| Restore from backup | A script and a measured duration | A restore into a scratch database |
Write down why, not what
There is one thing no amount of automation carries, and it is the reason behind a decision. Code states what the system does with complete accuracy and says nothing about the three alternatives that were considered and rejected, which is precisely the information the next engineer needs before changing it. Without it they will either preserve a constraint that no longer applies or remove one that still does, and both of those are expensive.
We keep these as short dated notes in the repository, one per decision, stating the context, the options, the choice and what would make us revisit it. They are a page at most. The last field is the one that earns its keep: a note saying "revisit if we exceed roughly fifty thousand records" turns a historical decision into a live trigger, and six months later somebody notices the threshold rather than wondering why the design is the way it is.
What we deliberately do not write is a description of how the code works. That document is a second copy of the code, it is wrong within a release, and reading it is slower than reading the code it describes. The exception is a single diagram of how the parts connect and where the data lives, which stays true far longer because it changes on a different timescale.
Hand over the ability to be on call
Operating a system is a separate skill from changing it, and a handover that covers only the code leaves the client able to modify something they cannot support. So the handover includes the operational surface: where the logs are, what the alerts mean, which alert is worth waking up for, and what the first three steps are for each of the failure modes we know about.
That last item is a runbook, and the useful form of it is short and specific rather than comprehensive. One page per alert, naming the alert exactly as it appears, with the first thing to check and the most common cause. A runbook that tries to cover every eventuality is not read at three in the morning; a one-page note titled with the exact text of the alert that just fired is read immediately.
The honest limitation is that we can only write runbooks for failures we have seen. So the handover also includes the mechanism for adding one: the next novel incident should end with a new page, written by whoever handled it, while they still remember. A runbook collection that only grows during the supplier engagement and then stops is a sign that the handover transferred artefacts rather than the practice that produces them.
The accounts are part of the handover
A handover that transfers the code and not the accounts has transferred the easy half. The cloud account, the domain registration, the repository with its history, the error tracker, the payment processor, the email sender — each one is a dependency that can be withdrawn, and a system you cannot deploy is not a system you own. This is the part that gets discovered six months later, when somebody needs to rotate a key and finds the account is in a former supplier’s name.
The check is mechanical and worth doing as a list. For every external service the system touches, write down whose name the account is in, who receives the bill, and who can grant access. Any row where the answer is the supplier is an item for the handover rather than a detail. The list is usually longer than anybody expects — fourteen rows is normal for a modest system — which is itself the argument for writing it rather than remembering it.
Credentials deserve their own pass. A handover should end with every shared secret rotated, because a password the outgoing team still knows is a password that is still in their password manager, through no bad intent at all. Rotating at handover is also the only time you find out which secrets are hardcoded somewhere nobody remembers, which is a discovery far better made on a planned afternoon than during an incident.
A runbook is written during incidents
Runbooks written at the end of a project are fiction, because they are written by somebody imagining what might go wrong. The useful ones accrete: every time something breaks, the person who fixed it adds the symptom, the check that identified it and the action that resolved it. After a year of that you have a document that describes the failures this system actually has, which is a different and much shorter list than the failures it could theoretically have.
Which means the runbook cannot be a handover deliverable created in the last week. It has to have been kept from the beginning, and the handover is where it is read aloud rather than where it is written. If there is no runbook at handover time, the honest response is to say so and to spend the handover period generating one from the incident history rather than from imagination — the ticket queue is a record of every real failure, and it is sitting there.
Each entry should be short enough that somebody reads it at three in the morning.
- The symptom as it appears.
- The one command that confirms the diagnosis.
- The action.
- What to do if the action does not work.
Anything longer is an essay and will be skipped. Four lines per failure mode, twenty failure modes, is a complete and genuinely usable operations document, and it is shorter than most handover decks.
The tests are half the documentation
A test suite is the only documentation that cannot quietly go out of date, because when it stops describing the system it fails. That makes it the most valuable thing in a handover and the easiest to undervalue, since it does not look like documentation. A new team’s first question is always "what will I break if I change this?", and a suite that answers that question in ninety seconds is worth more than a diagram that answers it ambiguously.
The tests that matter most at handover are the ones covering the rules nobody would guess: the invoice that rounds differently for one customer type, the status transition that is forbidden on weekends, the field that must stay blank for historical records. Each of those is a decision somebody made for a reason, and a test is the only place that reason survives staff turnover. Comments get deleted; a failing assertion gets investigated.
- Every business rule a newcomer could not guess.
- Each bug that has recurred, as a regression test.
- The full path of the one flow that earns the money.
- A suite that runs on a laptop in under two minutes.
And a suite the new team can run
A suite that only runs on the outgoing team’s machines, or only in a pipeline whose credentials leave with them, is a suite that has not been handed over. The acceptance test for this is the same first-morning test as everything else: a new engineer, on a new laptop, runs the tests and they pass. If that takes longer than an hour to achieve, the gap is part of the handover scope rather than a note for later.
The month after is part of the deal
No handover is complete on its last day, because the questions that matter only surface when the new team touches something unfamiliar — which happens in week three, not week one. A handover without a defined period of availability afterwards puts the new team in the position of either guessing or asking a favour, and both of those are worse than a priced arrangement agreed in advance.
What works is a defined and shrinking commitment: a named person reachable for a month, a response time that is honest rather than flattering, and a list of what the arrangement does not cover. The shape matters less than the fact that it is written down, because an undefined arrangement is the one that gets resented on both sides — the new team feels abandoned and the outgoing team feels permanently on call.
It is also the period in which the handover gets tested for real, so it is worth tracking what gets asked. Every question the new team has to ask is a gap in the documentation, and a question asked twice is a gap worth closing permanently. A handover that generates eleven questions in its first month and ends with eleven new runbook entries has done its job better than one that generated none because nobody dared touch anything.
What the last two weeks look like
On our projects the final fortnight contains no new features, by agreement at the start rather than by negotiation at the end. It is spent running the first-morning test with an outsider, having the client’s own team deploy and roll back a real change while we watch and say nothing, rotating every credential together, and restoring a backup into a scratch database to find out how long that actually takes.
Watching and saying nothing is the part that matters and the part that is hardest to do. The instinct when somebody hesitates is to take the keyboard, and taking the keyboard converts a successful handover into a demonstration. Every time we have given in to that instinct, the client’s team has been slower to take the system on afterwards, which is a cost we pay in the following quarter.
- A new engineer runs it locally in one morning, unaided.
- The client’s team deploys and rolls back while we watch.
- Every credential rotated once, together, and recorded.
- A backup restored into a scratch database, and timed.
- One runbook page per alert that can wake somebody.
- Dated decision notes with a revisit trigger on each.
None of this is expensive if it is built as the work proceeds, and all of it is expensive if it is left to the end. The scripts are written the first time the operation is performed, the decision notes while the decision is fresh, the runbook page at the end of the incident. Treated that way the handover is not a phase at all — it is a property the project has continuously, and the final fortnight is confirmation rather than construction.



