A patient paid ₹400 and got nothing.
No confirmation, no message, no appointment, no database row. The centre had the money and no record of her. Nothing alerted anybody — it was found by looking.
The diagnosis arrived before the evidence did.
Razorpay had no webhook configured
- It explains the symptom completely.
- It names a real missing thing.
- The missing thing was genuinely missing.
Every property of a correct answer except being one.
A webhook would have hit the same wall
- Turning a paid booking into records was failing regardless of who asked for it.
- Configuring the webhook would have changed nothing.
- And the failure would have looked fixed.
The wrong answer was not careless. It was arrived at by thinking about the system instead of reading what the system had already written down.
It took reading the log properly.
Transaction already closed: the timeout for this transaction was 5000 ms, however 6698 ms passed.
- Before
- Turning a paid booking into records — patient, appointment, order, payment, receipt — ran inside one database transaction with a five-second limit.
- What forced it
- Two helpers inside it, generating the next patient code and the next invoice number, used the global database client rather than the transaction's own. Each opened a separate connection and spent four extra round trips against a pooler in another region. The failure was two files away from where anybody was looking.
- The decision
- Move the numbering outside the transaction and raise the ceiling: twenty minutes of work. The transaction now runs with a twenty-second timeout, and the comment beside it says that is headroom rather than licence to do more.
- What it changed
- Then the redesign: three independent confirmation paths funnelling into one idempotent function, so no single path is load-bearing. The incident is written into the file as a comment, with the date and both numbers, so the reason for an unusual timeout value is where the next reader will be standing.
The lesson recorded from this is three words: verify, do not reason. The patient's booking was recovered by hand.
The lesson was recorded on 15 August. On 30 August it was needed again.
- 14 Aug 2026
The payment incident
A confident cause, asserted without checking, that would have produced a fix which appeared to work.
- 15 Aug 2026
Verify, do not reason
Written into the build log as the project's chief lesson, alongside the reliability redesign.
- 30 Aug 2026
fix: the assessment is twenty minutes, not ninety
The commit message, in the author's own words: I wrote "ninety minutes" onto the visiting-card landing page, the gift pages, the share posters and the printed card copy. Nothing in the system says that. I invented the number and it went live.
Removed rather than corrected. The commit argues the claim was never load-bearing — what the copy sells is that an assessment comes before anything is recommended — and that a duration, if wanted later, should read from the offering's own field, the way prices already do.
It is included because a study showing only the lesson being learned, and never the lesson being needed again, would be a flattering account rather than an accurate one.
Thirty seconds of looking beats five minutes of thinking.
| What was believed | What was true | How it was found |
|---|---|---|
| A brand rule had been violated in the markup. | The token configuration had already set that radius to zero. The class was a no-op. | By opening the token file. |
| The homepage had been broken by a change. | A stale development server was serving an old build. | By restarting it. |
| Three assumptions about another company's message templates. | All three wrong — where the code goes, how expiry is set, what the category permits. | By writing the setup guide. None surfaced as an error first. |
| A guard in a layout was protecting the pages beneath it. | Its thrown error was being silently discarded. | By reading the server log during a walkthrough. |
In most of these the wrong answer would never have produced an error. It would have produced a fix that appeared to work.
Techniques that replace reasoning with evidence.
- Writing the guide is a debugging technique — explaining a feature to somebody who will follow it exactly is the fastest way to find out you do not understand it
- Check the console before writing about the console — every assumption about another company's product turned out to be a guess dressed as knowledge
- Say it out loud to somebody else — the affiliate scheme was wrong in a way its author could not see until he described it aloud
- Walk the flow rather than reading it — a redirect loop was found by using the product, not by reading the code
- The reconstruction rests on the project's own logs, written by the person who made the mistake; the log line and the timeout values are checkable in the code, the sequence of belief and discovery is not
- 6,698ms is one logged line from one failed transaction — there is no load test and no uptime record, so nothing says how often this would have recurred
- Whether the reliability work prevented a second incident is recorded nowhere
You cannot find that by being clever about the symptom. You find it by reading what the machine actually said.
BUILD-LOG.md, chapter IV
Verify, do not reason.
Nirmalkaya · one of six perspectives on the same project