Skip to content
Hominis Agentic OS · early access program now openJoin the waitlist
RealAI

Case studiesBanking IT sourcing

Case study
Banking IT sourcingA European banking group IT services subsidiary

A technical review of one build, then a difference test against the build ten weeks later, found nothing that would justify starting user acceptance testing

A European banking group IT services subsidiary commissioned a forensic review of an offshore build that had reached its declared end of implementation and could not be handed to users. The review read the contract, the project record and the interviews, then did the thing the steering meetings had never done: it read the code. The first pass found design principle violations across the board, code coverage of roughly ten to fifteen per cent across the server and front-end stacks, a client-side cache used as shared memory with reads and writes landing in random order, server-side static variables holding session state, and service calls that did not check authorisation, shown by a penetration test. Then it ran a difference test against the build produced ten weeks later, at the end of a grace period granted specifically to fix those things. No improvement in quality or stability sufficient to allow user acceptance testing was observed. The statement of work was terminated and the work taken in house.

Ten weeksBetween the two reviewed builds, with no gain sufficient to enter user acceptance testing
Client
A European banking group IT services subsidiary
Duration
Five-week forensic review of a terminated offshore build
AI · RIDGE E72.7 N87.5ρmax 1.00
10-15%Code coverage across the server and front-end stacks
~2.5xGap between the client's effort estimate and the vendor's
> 2 monthsTo place the senior architect the client had asked for

One technical review of a codebase is an opinion with evidence attached. A vendor can always argue with it, and usually does: the reviewer saw a snapshot, the team was mid-refactor, the worst files were already scheduled. Two reviews of the same codebase ten weeks apart are a different kind of object. The first tells you what the software is. The second tells you what the people building it are able to do about what the software is, once they have been told, given time, and given a reason to care. That second reading is the one a steering committee actually needs, and it is almost never taken.

A European banking group IT services subsidiary had an offshore build that had reached its declared end of implementation and could not be handed to users. Delivery had been in escalation for months. The commercial relationship was intact at senior level and on fire at the delivery floor. What nobody had, after all of it, was a defensible answer to a single question: if we grant more time, will the software get better?

The challenge

The build had not failed for lack of understanding. The requirement specifications were accepted by the vendor and reflected back in reverse presentations, which is the standard comprehension check and it passed. Comprehension was never the constraint.

The commercial structure is where the first real signal sits. The client's own effort estimate came in at roughly one thousand person-days. The vendor's estimate for the same scope was more than two and a half thousand. A disagreement of that size is not a pricing dispute, it is two parties describing different systems, and the correct response is to find out which one of you is wrong. Instead the gap was bridged commercially: a clause splitting project savings evenly on early completion, distributed among the delivery team. The master agreement itself carried penalties and no credit regime at all. So the contract could punish lateness, and it could reward finishing early, and it had no instrument whatsoever pointed at coverage, maintainability, architectural integrity or authorisation. Those are the four things that went on to fail.

Delivery issues were visible within weeks and formally escalated in the steering committee less than three months in, first on code quality and later on data context. Sprints slipped and the backlog never came back. The client asked for a senior architect it believed could turn the build around; the request took more than two months to fulfil, by which point the review records it as too late. Mitigation ran through headcount rather than through skill in the front-end framework the team was new to, and each arrival needed onboarding from people who were already behind, writing more code on top of a design nobody had gone back and fixed. Capacity is not the constraint when design is the constraint.

Then a grace period of ten weeks was granted, explicitly so the vendor could make the application stable enough to enter user acceptance testing.

The approach

The review was scoped at five weeks, hypothesis first. Form the risks you expect to find before you open anything, then let the evidence kill them or confirm them. Contract, statement of work, project artefacts and interviews came first, which is the part most assurance work stops at, because governance material is easy to read and rarely decisive. Then the review read the code, at expert level, against the build declared complete at end of implementation.

What it found was not a list of bugs. Bugs are normal. It was a set of structural readings. Design principles were violated across all of them, with single responsibility named specifically: classes carrying too many unrelated concerns, cited to a file. Patterns were present in the codebase and not understood, dependencies resolved by auto-injection rather than stated, synchronous and asynchronous code mixed in the same place, observer subscriptions never balanced by unsubscribes, and framework source modified directly instead of extended through the mechanism the framework provides for exactly that. Code clones were widespread, meaning any single fix had to be propagated across a number of files nobody could count. The client-side cache had stopped being a cache and become shared memory, written asynchronously with no way for a reader to know whether the data had arrived, which produced race conditions where the order of reads and writes was random and you saw the old value or the new one depending on the run.

Two findings were worse than maintainability problems. Server-side static variables were being used to hold session state, which means one user session can reach another session's data, in a regulated financial application. And not all service calls checked for authorisation, demonstrated through a penetration test in which some calls executed for users who had no right to make them. Test coverage across both the server stack and the front-end stack sat at roughly ten to fifteen per cent, sourced from interviews rather than from a tooling report, which is worth stating plainly because the number was never on a dashboard anyone watched. Three areas were marked as not examined rather than quietly assumed fine, which is the kind of scope honesty a report loses credibility without.

This is the point where an assurance finding becomes something we sell. Reading a codebase once is a consulting engagement. Reading it every night and reporting the delta is a control, and it is the control that would have made this entire review unnecessary. Coverage floors, clone density, circular reference counts and authorisation checks on every route are all measurable in the build, mechanically, without a meeting. Our Platform work starts by wiring those signals into the delivery pipeline so the quality trend reports independently of the people whose bonus depends on the schedule.

The outcome

At the end of the grace period the review ran a code difference test between the build declared complete and the build released ten weeks later. That is the whole verdict. No improvement in quality or stability sufficient to allow user acceptance testing was observed.

The statement of work was terminated and the work was taken in house. The client went on to fix the circular references between modules itself and introduced a loader configuration that flags any new one as an error, which is the shape of every correct answer here: turn the finding into a gate the build enforces, not a line item in a report.

What would be done differently now is not a different judgement. It is a different clock. Everything the review measured by hand is machine-measurable, and most of it already sits in the repository, the pipeline and the ticket system. Coverage, clone density and layering violations come out of static analysis on every commit. Escalation response latency, which is the number that actually decided this engagement, is sitting in the ticket timestamps and nobody was reading it. Process mining over the delivery record would have shown the backlog curve failing to bend a full quarter before anyone argued about it in a steering committee. A quality trend is cheap to produce continuously and expensive to produce once, and the terminating decision needs the trend, not the snapshot.

The current wave of cautious language-model pilots in code review changes the cost of the first reading and none of the arithmetic after it. A model that summarises a diff well still needs somebody to have decided in advance what would count as improvement, and to have written that down before the grace period started rather than after it ended. Set the threshold first, measure against it on a fixed cadence, and the second data point does the arguing for you.

Two builds ten weeks apart is not an anecdote. It is a trend with two points in it, and it is the trend that decides whether more time will help.

NEXT STEP

Ready to make AI real?