← All notes
How we work

The handover

A handover is a pass/fail drill on production, not a folder of documents. The engagement is designed to end.

27 Aug 2026 14 min EN · ES

On the homepage, the last step is called Exit. Most consultancies fill that box with documentation, runbooks and training. That sentence is the failure mode. A handover you can file is not a handover. A handover you can fail is.

This note is the long version of that step, written for someone who has already paid a consultancy that never left, or is about to sign and can hear that objection in silence. The engagement is designed to end. If eighteen months later you still cannot deploy without us, we failed. If you structured the contract so you never had to look, you failed.

Why most handovers fail

Because they are documents, and a document cannot be tested. It can be complete, approved and unread. The day you need it, the person who wrote it is on a plane. The test of a handover is not that somebody signed a PDF. It is that somebody who stays can ship and roll back while we are, by agreement, not in the channel.

A wiki written from memory at two in the afternoon does not replace watching the person open the console, hesitate and correct themselves. A runbook that has never been executed on production is a draft. “We’ll still be on Slack” is not a plan. It is debt with interest and no SLA.

If what you are handing over does not fit in a path from commit to production that somebody on the team can explain on a whiteboard, there is nothing to hand over: there is a half-finished platform programme. That path is one path to production.

What we actually hand over

It is not a folder. It is an inventory with an owner, a path in the repo, and proof that somebody who is not us can open it. Eight pieces. If one is missing, the handover has not happened: it has been documented.

  1. The repos. Yours, with history, not a zip at the end. Admin on the org, not a fork of ours that you will “migrate later”.
  2. The modules. Terraform or Pulumi that encapsulate decisions: an apply does not require the person who wrote them. A snowflake in the console is not a module.
  3. The runbooks. One page, executed, with a last-run date and the name of whoever typed. Deploy, rollback, restore, “the site is down”. Four. Not the wiki.
  4. The dashboards. The five the “site is down” runbook names. The rest is noise that can be rediscovered.
  5. The alert definitions. In code, the ones that earn the page. A Grafana export without on-call routing is a poster.
  6. The policy bundle. What the plan is not allowed to apply. In the repo, over the plan, not in a “best practices” PDF.
  7. The credentials model. OIDC per job, named humans in the IdP, audited break-glass. No vendor laptop as the glass key. The day we leave, none of our identities should still be able to deploy.
  8. The decision log. Why things are the way they are. It is the piece nobody ships, and it is the one you miss six months later.

The handover manifest is that list, with paths. It is not a report. If a reviewer who does not own the system cannot open a row in five minutes, that row is a gap, the same as in a compliance checklist.

The decision log is the part nobody ships

Six months later the question is never “how does this work”. It is “why is it like this”. How can be rediscovered: you open the module, you read the resource, you try. Why is lost: it was a Slack thread, a call, a “we talked it through with the vendor”. The log is not architecture. It is the context that is no longer in the room.

One entry per decision, in docs/decisions/, numbered. Immutable once accepted. To change a decision you write another that supersedes it. You do not edit the past. The format fits on one page:

# DEC-{NNNN}: {short title}

Date: {YYYY-MM-DD}
Status: proposed | accepted | superseded by DEC-{NNNN}
Deciders: {names and roles — the people who will still be here}

### Context
What was true when we decided. Constraints, incident, bill, deadline.
Not the architecture. The situation.

### Decision
One paragraph. What we will do, in production, from this date.

### Consequences
What becomes easier. What becomes harder. What we now refuse to do.

### Why not the alternative
Name the option we rejected and the reason.
"We didn't think of it" is not a reason.

### Review by
{YYYY-MM-DD} — or "when {event}".
A decision without a review date is a habit, not a decision.

An example, anonymised, from a finished engagement. The incident that provoked it lasted eleven days. The log is twelve lines.

# DEC-0014: Promote by digest, never by moving tag

Date: 2026-04-03
Status: accepted
Deciders: platform (A.R.), backend lead (M.S.)

### Context
Staging and production drifted for eleven days because :prod and :main
were retagged under a canary. The rollback button rebuilt main. main
had moved. The rollback shipped a different image than the one we had
just declared known-good.

### Decision
Every promotion specifies an immutable image digest. Tags are labels in
the registry, not addresses. The deploy runbook writes the digest before
and after. Rollback is `promote $PREV_DIGEST`.

### Consequences
We cannot "just rebuild". A broken build on main does not block a
rollback. The registry bill grows with retained digests; we keep the last
N known-good and garbage-collect the rest on a schedule.

### Why not the alternative
Moving tags (:prod) look simpler and make the UI one click. They also
make every rollback a rebuild, which is how we got the eleven-day drift.
Helm `latest` is the same mistake with a different name.

### Review by
2026-10-03 — or the first time a rollback takes longer than the time
budget in the runbook, whichever comes first.

If you cannot write the “why not the alternative”, you have not decided yet. You have preferred. The log does not forgive that difference, which is why almost nobody ships it: it records what was rejected, by name.

The drill

A full working day on which, by agreement, we are unreachable, and the client team ships and rolls back on their own. Announced, dated, on real production. Not a staging that does not resemble it. Not a “when you can”. Not a pairing session in which we type “just in case”.

The rules, said out loud two weeks before:

Pass: both things happened without us, inside the runbook’s time budget, and the runbook was updated with the date and the name of whoever typed. Fail: they called, or they could not, or they invented a step. A fail is not a drama. It is the next week’s work, with us still in the room. Exiting after a fail is how you manufacture the consultancy that never left.

If the drill is postponed once, it is re-dated in the same meeting. If it is postponed twice, the postponement is the finding: the system is not transferable yet, or there is nobody on the other side to receive it. We do not exit. We do not pretend the wiki was the exit.

What happens after

A defined support window, then nothing, then — if you want — optional quarterly check-ins. The window is a taper, not a subscription.

Phase What it is What it is not
Window (e.g. 30 days, office hours) Questions the runbook should have answered. Each one that needs us is a patch to the runbook, not a reason to stay. On-call. Not nights, not “we’re in the channel just in case”.
Nothing The contract ended. Our identities, revoked. The Slack, closed. “Still available”. That is notice in reverse, with no price and no date.
Quarterly check-in (optional) A booked day, a paid day, a written agenda. You look at the decision log that should already have come up for review. A monthly retainer under another name. If it becomes monthly, call it a retainer, or hire somebody.

If the quarterly check-in is becoming the operations model, you do not have a handover problem. You have a staffing problem. The arithmetic for that decision is in hire a platform engineer, or outsource it.

Where this breaks in practice

Artifact: runbook and decision log, to copy

Two files, in English, for the repo. The runbook is filled in while it is executed, not afterwards. The log is written on the day of the decision, not in the week of the handover.

# Runbook — {service}

Owner (the person who types, not the person who wrote this): {name}
Last executed: {YYYY-MM-DD} by {name} — result: pass / fail
Time budget: deploy {N} min · rollback {N} min

## 1. Deploy
Previous known-good digest: {sha256:…}
1. Open {path} on main. Confirm the merge you intend to ship.
2. Pipeline {ci-url}: {blocking-jobs} green. Do not skip {policy-job}.
3. Promote the digest, not a tag: {promote-command-or-ui}
4. Watch {dashboard-url} for {N} min. Abort if {abort-criteria}.
5. Write the new digest here and in {where-digests-live}.
Proof: production reflects the change — {how-you-see-it}.
A green pipeline is not this proof.

## 2. Rollback
Command: {rollback-command}
Expected time to previous traffic: {N} min.
Rollback does not undo: migrations {none|list} ·
queued messages {none|list} · flags {none|list}.
Proof: traffic is on the previous digest.

## 3. If this runbook cannot be followed
Stop. Do not invent. The drill failed. Write the step
and the error in docs/handover/drill-log.md.

The manifest we send at the close of an engagement is that list of eight, with paths in their repo, plus the date of the drill, the result, and who typed. It is not a case study. It is the same inventory, filled in.


Ask us for the handover manifest from a finished engagement. We will send an anonymised one. hola@pikas.systems