Ledger · 6 misses

Things I got wrong.

Each entry follows the same order I use at work: what happened, the root cause, what it cost, what I changed. A record of successes alone is a report nobody should trust.

  • I closed a project on a report I never verified

    cost · A quarter of false confidence; a reopened project

    I closed out a client marketplace project on the strength of a status report: feature-complete, hardened, every acceptance scenario passing, no known bugs. It was specific and confident. I accepted it and moved the record to closed.

    It was wrong on the counts that mattered. Months later an independent structural review found mocked flows and unauthenticated server actions in what had been reported as production-ready. The client's own product owner followed with a list of real defects. I had to reopen a project that had been tracked as closed for a full quarter.

    The root cause was simple. Nothing in how I ran closure distinguished a claim from a verification. The report was detailed and consistent, which felt like evidence. It was a person's account of their own work, and I never checked it against the code.

    What changedClosure now requires a check that does not route back through the person whose work is being checked. A suspiciously clean report is a reason to look, not a reason to relax.

  • Running six roles at once made volume my only proof of value

    cost · A month without buffer; judgement traded for output

    For a stretch of this year I held six simultaneous player-coach roles — building and directing at once — across client engagements and my own ventures, with no one to hand the build to. At the peak I touched twenty projects in a day and worked through weekends for a month.

    The deeper cause was not hours. With every role demanding both hands-on build and direction, the only legible proof of value was how much I had shipped. That is a bad trade twice: nobody outside the work can tell judgement from busy hands, and the hands-on slice is exactly what AI coding tools were starting to commoditise.

    Working harder inside the same structure would not have fixed it. I mapped every engagement to keep, hand off or drop, and found that on nearly every one, someone capable of owning the build was already on the roster.

    What changedI shed the build and kept the seam: measurement, costing, and the connection between a technical system and a business outcome.

  • My own venture lost to client work — by default

    cost · Months of stall at the point it was closest to launch

    Replate is a real clinical-nutrition practice going digital. Most of the build shipped — authentication, booking, vitals, plans — and then it went quiet for months, exactly when it was closest to launch. What stalled was not the code. It was everything after the code that needed a decision from me and had no client deadline forcing it.

    Five of my six roles had a paying client and an external date attached. One — my own venture — had neither. A venture with no external deadline does not lose a fair fight for attention. It loses by default, silently, without anyone deciding it should.

    The cost was not cosmetic. The operational work that protects people's data had fallen behind the product, and that is the kind of debt you do not get to repay later.

    What changedI reprioritise by irreversibility, not by who is asking loudest — the risks without a do-over come first. And 'nobody is forcing this' no longer means 'this can wait'.

  • I built a careful comparison on a field I could not see

    cost · A confident, wrong conclusion

    I compared two records that had gone through identical treatment under a scoring system and drew a clean conclusion. It was wrong. The two differed on a field my own tooling did not show anywhere in the comparison view.

    The execution was careful and correct given its inputs. The mistake was treating 'this comparison was rigorous' as if it also meant 'this comparison saw everything relevant'. They sound like one claim. They are two.

    What changedEvery comparison I present now states which fields the tooling could not read. An unlisted field is a stated gap, not a silent assumption.

  • Three weeks of finished engineering shipped to a branch nobody ran

    cost · Three weeks; sixty-seven files that never ran anywhere

    An internal outreach tool received three weeks of real, late-stage engineering: drafting as the signed-in user, ranked proof points, model observability, per-draft cost reporting. None of it ever ran. The branch was never released, and by the time it would have been, the initiative it served had been discontinued.

    The code was tested and working. The failure was that I kept building against a business decision I had not re-confirmed. Engineering has one cadence and the business decision had another, and I let three weeks pass without a checkpoint connecting them.

    What changedBefore committing weeks to a build, I re-check that the thing it serves is still true. Closing out, open work stays marked as stopped, not quietly marked done.

  • I let the working half of a pricing tool vouch for the other half

    cost · A decision gate that could not say which half to trust

    A pricing engine had two layers: a cost corridor, real and tested, and a value layer meant to weigh what a customer would pay. The value layer never got calibrated — the history of past deals it needed held two rows at handover.

    That alone is not a failure; young tools are short on history. The failure was letting both layers sit in the same demo and the same handover without a hard line between them. A working demo of one layer implicitly vouches for the layer beside it unless someone says otherwise. Nobody did, including me.

    What changedEvery handover now labels, separately, which numbers are backed by outcome data and which are structurally sound but unvalidated.

Reflections

What the misses left behind.

A check is only as honest as its name

The most common defect I find is a check that answers a narrower question than its name promises. A gate called “no override path” means “no override I pattern-matched”. The fix is not more checks. It is reading a check's name as a claim, and asking what would falsify it, before trusting a green result.

The report and the effect are two things

A tool computes a result in one place and prints its verdict in another, and nothing compares them. I have watched a success line print for eleven days while nothing was written. Read the row, the file, the rendered page — not the line claiming it happened.

Right number, wrong story

A verified count answers how many. It never answers why. The most expensive damage I have done came from narrating a mechanism a count never established — because the story, not the number, is what gets acted on.

Drift is not quality

“Thirty-three percent of outputs changed” is the size of a change, not its direction. I once rejected a change on drift alone; scored against the labels already in the corpus, the rejected arm was more accurate.

Evals measure the software, not the work

Suites drift toward what is cheap to check — did it parse, did it route — and away from whether the output was any good. Build the coverage matrix first. The hole shows up as a column of zeros.

Compliance is not outcome

Adoption is visible in days. Improvement needs weeks. A leadership report that collapses the two will eventually meet a reader who asks the outcome question, and the whole initiative's credibility rests on having a real answer.

The long versions, in the essays →