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

Case studiesBanking IT services

Case study
Banking IT servicesA European banking group IT services subsidiary

The statement of work named a design standard and named the supplier's own process as the thing that would prove compliance, and the codebase violated every principle in the set

A European banking group IT services subsidiary commissioned a post-mortem review after an offshored front-end build failed to reach acceptance testing. The statement of work committed the supplier to a named set of object-oriented design principles and named the supplier's own internal quality process as the mechanism that would validate compliance. The review read the delivered codebase and found violations against every principle in the set, evidenced by one named source file and six tracker tickets across four groups of findings. Automated test coverage sat at roughly 10 to 15 percent across the two stacks, the supplier had run no vulnerability assessment and no penetration test, and the design document that would have made the clause checkable was never produced. The output was a findings pack and a list of recommendations, not a repaired application.

Every principlePrinciples in the contracted design set with a violation found against them
Client
A European banking group IT services subsidiary
Duration
Post-mortem review after an offshored build failed to reach acceptance testing
AI · RIDGE E72.7 N81.3ρmax 1.00
6Tracker tickets, plus one named source file, behind the design findings
10 to 15%Automated test coverage across the two stacks
0Vulnerability assessments or penetration tests run by the supplier

A contract can name the standard a supplier will build to, name the process that will prove compliance with it, and still leave nobody outside the supplier in a position to check either. That is not a drafting mistake. It is the ordinary shape of a software quality clause, and it is why so many of them survive a failed project untouched. Nothing in them was ever measured by the party paying.

A European banking group IT services subsidiary commissioned a post-mortem review after an offshored front-end build failed to reach acceptance testing. Most of the questions put to that review were about governance and money. One was narrow and answerable. The statement of work had committed the supplier to deliver software built on a named set of object-oriented design principles, and had named the supplier's own internal quality process as the mechanism through which that compliance would be validated. So: had it been?

The review read the delivered codebase and found violations against every principle in the named set. Not most of them. All of them. Where it could be specific it was specific: one source file cited by name, and six tracker tickets spread across four groups of findings. Where it could not, it said so, and one violation is the only one it itemises against a principle by name.

The challenge

Read the clause again and the failure mode is visible before any code is opened. Two commitments were made, and the second swallows the first. The supplier would build to a standard, and the supplier would run the process confirming it had. Everything in that sentence sits inside one organisation. The buyer's assurance was a promise that the seller was checking its own work.

There was supposed to be a bridge between the two. The statement of work carried a costed line for a system design document that would set out coding standards, design principles and the supplier's rationale for the development approach. The review found no evidence it was ever produced. That artefact is the only thing in the whole arrangement that could have made the clause auditable, because a principle stated in a contract is an aspiration until somebody writes down what conformance looks like in this codebase, on this framework, for this team. It was priced, it did not appear, and no control in the project noticed.

What the review found instead was a codebase in which the patterns had been reached for and not understood. View models were pushed back to the server carrying model data with them. Dependencies were auto-injected rather than declared, so what depended on what could not be read off the source. Synchronous and asynchronous code sat mixed in the same place. Subscriptions to the observer pattern were opened and never balanced by an unsubscribe. The team modified the framework's own source rather than decorating it. The consequences the review listed follow mechanically: code that is expensive to change, unpredictable results from race conditions, wasteful use of the network, memory leaks.

Loading exhibit
Exhibit 1Every bar clears the line the contract drew.The contracted design set as a field over a plane. The plane at zero is what the clause asserted would be true. Height is the evidence the review puts behind each commitment: a base unit for the code inspection, one more per tracker ticket, one more for the one source file the report names. Six red cubes are the six tickets. The front row holds the single principle violation the review itemises beside one wide open cage, which is the rest of the set: the review says it failed and never says by how much, so the cage stands at the floor rather than carrying a count nobody wrote down. Nothing in the field touches the plane.

The picture is the argument. A clause that asserted a flat, clean floor produced a field in which nothing comes back down to it, and the tallest columns are simply the ones somebody happened to log a ticket against. Evidence density is a record of attention, not of severity.

The approach

Two other findings show what an external test would have caught and when.

Automated test coverage across the two stacks sat at roughly 10 to 15 percent. That is not a code review finding; a build server produces it on every commit, for free, from week one. Nobody outside the supplier was reading it. The review also examined two builds roughly ten weeks apart and ran a difference test between them, finding no improvement in quality sufficient to allow acceptance testing to begin. That comparison is mechanical too, the kind of thing a pipeline does while people sleep.

The security findings have the same shape. The supplier ran neither a vulnerability assessment nor a penetration test. When a penetration test was eventually run, some service calls turned out to be executable by users with no authorisation to make them, and the front end was in the habit of inventing a missing property locally and posting it back to a server that took it on trust. There is a version of that defect that reaches a customer's data. It was found late, by an outsider, because no continuous check existed to find it early.

And the module layering was worse: the codebase carried circular references between modules. Those were fixed by the buyer's own engineers, who introduced a loader configuration that now flags a circular reference as a build error. That is the moment the whole story turns. The buyer built the automated test the clause should have implied, after the project it was meant to protect had already failed.

The outcome

What this engagement produced was a findings pack and a set of recommendations, not a repaired application. The build had already ended. Five of the recommendations addressed exactly this gap: agree design and coding standards up front, specify guidance on the patterns to be used, use automated tooling to enforce quality, run peer code review rigorously, and follow established development practice. None of them was new. They are what the contract had already gestured at. The difference is that a recommendation to use automated tooling names an instrument, and a clause naming a principle set does not.

One detail shows that a process running is not the same as a process working. A category of typing defects was raised early, logged in the tracker, tracked, and closed by agreement between both sides. The same class of fundamental error persisted anyway. The property those tickets were supposed to protect was never measured, so closing them changed the ledger and not the codebase. A control that reports on its own activity will always look healthy.

If the same clause were written today, the honest version would be shorter and harder. Name the standard, then name the check: the coverage threshold below which a build fails, the static analysis rules that must pass, the dependency graph that must stay acyclic, the security scan that must run before a release is offered for acceptance. Publish the results to the buyer continuously rather than reporting on them monthly. That is the discipline MLOps borrowed for models, where lineage and automated validation gates became normal precisely because nobody could tell by looking whether a model had drifted. Software was always in the same position; it just had a longer tradition of pretending otherwise.

The lesson generalises past code. Any clause that commits a supplier to a quality property and then nominates the supplier's own process as the validator is a clause that measures nothing. That is as true of a data quality commitment in a feature store contract, or a straight-through processing rate in an operations agreement, as it is of a design principle in a build. The Platform work we do puts the check where the buyer can see it, because assurance that lives only inside the party being assured is not assurance. It is a courtesy.

NEXT STEP

Ready to make AI real?