When a software project fails, the review usually starts with the team. Who was skilled, who was not, which escalation went unanswered, which sprint slipped. The contract is the better place to start, because it is the one document that says out loud what the buyer agreed to pay for, and it says it before anyone writes a line.
I led a post-mortem review of a failed offshore build commissioned by a European banking group's IT services subsidiary, covering the master agreement and the statement of work, the project artefacts, interviews on both sides, and a high-level expert review of the codebase. It produced findings and recommendations, not a rescue. The engagement had ended.
The finding I still use most often is not about the code. It is about one paragraph in the statement of work.
The clause
The mechanism was simple and reasonable. In the case of early completion of the project activities, the saving would be split evenly between the client and the supplier, and the supplier would distribute the resulting revenue pro-rata among the project team.
The estimates were far apart, roughly a thousand person-days on one side against over two and a half thousand on the other, and the review found no evidence of the methodology behind the estimates. A profit-sharing term is a sensible way to close a gap you cannot argue to a conclusion.
What makes the clause worth writing about is the second half of the sentence, the part pushing money past the supplier's accounts and down to individuals. A saving split between two companies is a commercial preference and it lives in a steering meeting. A saving distributed pro-rata among the project team is a personal preference, and it lives at the desk of the developer deciding, at four in the afternoon, whether to extract the shared function properly or paste the block a third time.
Nothing else in that contract reached the developer. Not the penalty regime, not the escalation path, and not the quality expectations, which were written as intent rather than as terms that moved money.
What the contract priced, and what it did not
Read a delivery agreement as a list of things somebody is paid to produce and its shape comes out quickly. Lateness had a price, in the master agreement's penalty scheme. Earliness had a price, shared down to the person. Better-than-expected performance had no credit regime. Maintainability had no price at all.
The clearest casualty is the design document, estimated in the statement of work at 140 person-days: coding standards, design principles, and the reasoning behind how this system would be built. The review found no evidence it was ever delivered.
Sit that deliverable next to a clause that splits savings and it becomes the most attractive thing on the plan to skip. It produces no visible feature, it delays the first demo, its absence is invisible for months, and under the profit-sharing term the money saved by skipping it goes partly to the people who would otherwise have to write it. I am not claiming anyone made that trade cynically. I am saying the structure pointed the honest choice and the profitable choice in opposite directions, and left nobody with a reason to notice.
The signature in the codebase
The technical findings read like a list of decisions that each save an afternoon.
Duplicated code appeared in two forms: repeated blocks differing only in small details that should have been a call to a private function, and lines copied into different areas of the codebase that should have been a service call. The review recorded the consequence plainly, that a bug fix now has to be propagated across an unknown number of files.
Caching was done at the client, case by case, and used less for efficiency than as a shared memory area any part of the application could read, written asynchronously with no way for the reader to know the data had arrived. The same screen would sometimes show old values and sometimes new. Session state on the server sat in static variables, so with several sessions active one user could reach another's data, in an application handling customer investment information. Some interface calls did not check for the right authorization, and a penetration test executed calls as users who should not have been able to make them. Automated test coverage stood at approximately 10 to 15 percent.
Every one is faster on the day than the alternative. Copying beats extracting a function, a static variable beats a session store, a skipped authorization check beats a written one, thin coverage beats thick. And none of them changes what a reviewer sees in a demo, which is where completion gets judged.
I want to be careful about the causal claim. The review found several contributing causes and I would not put the whole failure on one paragraph. The team was working with a front-end framework it had not used before, depth of experience was thin, the answer to slipping sprints was more people rather than a look at the design, and escalations reached senior management on both sides without reaching the execution layer. But the incentive question is the one nobody asked while the project ran, and the profit-sharing clause was the only term in the structure that reached an individual developer.
- Split evenly
- Early-completion saving, then pro-rata to the project team
- 140 person-days
- Design document estimated, no evidence it was delivered
- 10-15%
- Approximate automated test coverage at review
- Penalty only
- Master agreement scheme, no credit regime
Adding people multiplies the pattern
When the backlog appeared, the response was to ramp the team, scaling from twenty to thirty on one occasion. The review records the effect: teams developing their own modularised pieces hierarchically, without sight of the whole. That is what adding people to a duplicated codebase does. New arrivals are judged on how quickly they become productive, and where the working pattern is already copy-and-adapt, the quickest route to a feature is another copy. The clause rewarding early completion did not pause while the team grew.
Meanwhile the one term with teeth on the downside went unused. The penalty clause was waived, and the review recorded that waiving it did not help the collaboration. The structure ended with its speed incentive live and personal, and its quality incentive switched off.
A clause that shares a saving with the people producing it does not stay a commercial preference. It reaches the desk of the developer choosing between a refactor and a copy, and it has already answered the question.
Why I bring this to machine learning work
I keep returning to this build in conversations about machine learning pipelines, because that work is bought in the same shape: fixed scope, a delivery date, a demo that decides whether it succeeded.
The expensive part of a model in production has never been the model. It is the pipeline somebody has to keep running: where each feature came from, what it meant when it was computed, whether the training path and the serving path agree, what the person on call reads when a score drifts at three in the morning. A feature calculated one way in the training job and another way in serving is the duplicated block from that codebase, with the difference that the model will not crash. It will quietly be a little wrong, and the demo will still pass.
Lineage, feature definitions written down, a data readiness pass before the pipeline: those are the 140 person-days, and the first items priced out of a proposal. They produce nothing anyone can watch, and nothing in the commercial terms fires when they are missing. The early language-model pilots crossing my desk are demo-shaped for the same reason. A pilot is judged on the date it demonstrates, so it is built for that date, and nobody has been paid to make it operable a year later.
So the test I run on a delivery agreement is short. List every clause that moves money, then ask which would fire if the system arrived on schedule and turned out to be unmaintainable. If none would, quality there is an expectation rather than a term, and expectations lose to terms every time.
What we would have written instead
Pay for the design deliverable separately and gate payment on its existence, so the description of how the code will be built cannot be absorbed into a saving. If a saving is shared, measure the state at handover as well as the date: coverage, duplication, automated quality gates named in the agreement rather than assumed. Put a credit regime opposite the penalty regime, so there is something to earn by being good and not only something to lose by being late. And interview the people being contracted, including the ones running delivery, which here did not happen.
None of that requires trusting a supplier more. It requires the contract to pay for what you want, which is a system that still works once the people who built it have moved on. Writing those terms is the opening block of a RealAI Consult engagement.
Figures are as recorded in a post-mortem review of a failed offshore software development project commissioned by a European banking group's IT services subsidiary: its master agreement and statement of work, its project artefacts, interviews on both sides, and a high-level expert review of the codebase. That review produced findings and recommendations after the engagement ended, not delivered results. Reading the commercial structure as the origin of the code quality is ours.
“A clause that shares a saving with the people producing it does not stay a commercial preference. It reaches the desk of the developer choosing between a refactor and a copy, and it has already answered the question.”
Get in touch
Put RealAI’s applied-AI team on your hardest data problem.
We help enterprises move from pilots to production: sovereign models, governed data, and agents you can audit. Start with a value-first assessment.
