Case study — Legacy succession

Every module had one owner who knew it cold. That was the problem.

We were hired to find out whether AI-assisted development could help maintain a thirty-year-old codebase. It could. That turned out to be the less interesting half of the answer.

The problem.

A software company of around ten people, with a workforce-scheduling product that has been running in production for three decades. Its customers are large organisations that staff around the clock, where a published schedule is a regulated commitment and the rules differ by site, by contract, by agreement. The business logic is the product. Get it wrong and it shows up in someone's pay.

The technical situation was what you'd expect and slightly worse. Hundreds of units of a language most developers have never written, plus a solver in another language, plus a modern web front end, plus the service layer bridging them. Version control from 1982 — per-file, no atomic commits, no branches — wrapped in an in-house layer built up over many years. No continuous integration. No code review. No automated tests.

None of that was negligence. It predated the practices, and nothing had ever forced the question.

Here is the part that matters, and it is not what you'd guess.

This was not a lone developer with an orphaned codebase. It was a competent team with clean division of labour. One engineer owned the scheduling core. Another owned the solver. Another the data layer, another the web application, another the infrastructure. Each knew their own territory in depth. Coupling between them was low. Responsibility was unambiguous.

By most measures, that is a well-organised engineering team.

It also means every pillar is a single point of failure by construction. And the engineer who owned the core — the one whose territory was the product — had announced his retirement.

Twenty days to form a view.

What we built.

We refused to answer with a slide deck. You cannot assess whether a tool helps maintain a system by discussing it.

The point was never the feature.

The question on the table was whether developers could work productively in a thirty-year-old codebase written in a language they had not mastered. The only honest way to answer that is to do it — on the real code, in the real application, with a real business requirement that nobody could wave through.

So we took one: reconstructing what a published schedule looked like at the moment it was committed, so it could be compared against what was finally worked. The gap between those two carries legal and payroll consequences. It touches the oldest, least-documented machinery in the product. And its central subtlety is the kind that punishes outsiders — the deadline governing it is not a fixed number of days but a rule, written differently by different customers, some anchored to a date and some to a calendar month. The thing you would naively store as "how many days ahead" is not a number at all. It changes depending on which day you ask about.

We built it end to end. The core decision logic was isolated into a unit with no database and no framework dependencies, and covered by tests. It compiled, ran inside the real application, created its own tables, and processed a full month of real scheduling data without touching anything the existing system depended on.

That answered the question it was built to answer. What was delivered alongside it mattered more.

A test suite. The team had a testing idiom already, but scattered and never run systematically. We consolidated it into just under two hundred passing tests over the genuinely reusable logic — dates, durations, sorting, the core selection rules — runnable in one command, with an exit code and machine-readable output. It plugs into a CI pipeline the day one exists. It is the floor you need before anyone can refactor without fear.

A knowledge asset. A structured, installable companion capturing what the code alone doesn't say: how the modules relate, what the domain vocabulary means, what breaks if you change a given thing, how the legacy version control actually behaves.

A way off 1982. The team's version control was the single largest drag on everything else — no atomic commits meant no reviewable change, no branches meant no parallel work, and no CI could ever be attached to it. But a big-bang migration of a thirty-year history across dozens of projects is exactly the kind of initiative that gets started once, stalls, and poisons the idea for a decade.

So we built a converter that moves one repository at a time, preserving full history, correct authorship, and release tags — including the conventions the in-house layer had added on top, which we recovered by reading its source. Projects move when there's a reason to move them. Everything else keeps working untouched. Two repositories went across during the engagement, verified against their originals.

The part that isn't in the deliverables.

When you replace the tooling somebody has maintained for years, you are not making a technical change. You are telling a colleague, in front of their team, that the thing they built and looked after is finished. Do that badly and you don't get resistance you can argue with — you get polite agreement and a migration that never quite happens.

The engineer who maintained that version-control layer had built it, extended it, and kept it working for a long time. That work was genuinely good. It solved real problems for real people, for years, on a substrate that gave him very little to work with.

So we didn't pitch Git to him.

While building the converter, we asked him about the old system instead — how it worked, what the conventions meant, how the team actually used it day to day, what it handled that nobody had noticed. The interest was not a technique; the system was legitimately interesting, and understanding it was the only way to convert it correctly. Nothing in those conversations was an argument for replacement.

Then we did the opening work ourselves. Built the converter, ran it, proved it on two colleagues' repositories until those were running on Git with their history intact. No proposal, no deck. A path that visibly worked, walked first by us rather than recommended to someone else.

And then we showed him.

He took it and ran. He has since put substantial work into the converter himself — including on his own time, which is the part worth paying attention to. Nobody assigned that. Nobody could have.

That is the whole outcome, and it is the only reliable measure of a change being adopted rather than tolerated: the person with the deepest knowledge of the old system is now the one improving the thing that supersedes it. Nobody was told their work was obsolete, because it wasn't — the conventions he had built were precisely what the converter had to understand, and his expertise became the most valuable input to the migration instead of its casualty.

The lesson is not that he was won over. It's that he was never the obstacle. The obstacle is the way these changes are usually introduced.

Two rules made that work, and they generalise.

Never say the diagnosis out loud. Reading a situation as "the senior engineers are attached to tools that are part of their professional identity" can be useful for deciding what you do. Saying it to anyone lands as an accusation, and it's frequently wrong besides — in this engagement one such reading turned out to be plainly incorrect, and we only found out because we asked the person about their work instead of telling them about themselves.

Go first. The distance between "you should migrate" and "here is the migration, it works, here's how it handles your conventions" is the entire distance between advice and leadership.

Why it was hard.

The code compiled. It passed its full test coverage. It was still wrong in five places.

Every one was caught by the same person — the engineer who owns the core — and every one was the same category of wrong. Not a bug. A misunderstanding of why the system is shaped the way it is.

One is worth telling properly, because it generalises.

Our version of a data-writing routine deleted rows and reinserted them. Clean, readable, obviously correct. What it discarded was a mechanism that only updated what had actually changed — a mechanism that exists because, years earlier, the job used to run for an unacceptable length of time doing exactly what we had just reintroduced. Someone diagnosed that, built the optimisation, and moved on.

The resulting code is more complicated than the naive version, and nothing in it explains why.

That is the general shape of the thing: an optimisation is a scar. It is the mark left by a problem that no longer occurs, precisely because the optimisation is there. Anyone encountering it fresh — human or machine — sees unjustified complexity and simplifies it. The old problem returns, and nobody connects the two events.

The other four were variations on the same theme. Each required knowing a decision's history. None was detectable by a compiler or a test.

That is the first finding, and it is the one people expect: AI amplifies expertise, it does not manufacture it. Point it at a domain without domain knowledge at the wheel and you get output that is plausible, tested, green — and wrong in ways nothing automated will catch.

But the engagement produced a second finding that mattered more, and we found it by accident.

We had structured the work as a delegation loop. The tool proposes, the expert reviews, we iterate. His engagement was total — he built his own test harness, checked results by hand, and when a crash hit he reproduced it, traced it, disabled the offending code, re-ran the entire job to completion, correctly identified the code as a leftover from an earlier iteration, and reported all of it. He proposed the right architecture and we adopted it exactly as proposed. He volunteered observations nobody had asked for.

At the end of six weeks of that, the person who understood the design best was still him.

The knowledge had flowed the wrong way. Work went out as a question and came back as a solution — and a delivered solution teaches nobody anything.

This needs naming precisely, because it is counter-intuitive: it is not a lack of engagement. It is the opposite. Solving and transmitting are different activities. Transmitting is slower, less satisfying, and while you are doing it the problem stays open. Someone who genuinely enjoys solving problems will go, in good faith and every single time, straight to the solution. Decades of that accumulate an extraordinary amount of knowledge — not through hoarding, but through appetite.

And this is why a strong team does not fix it. Clean module ownership means the same mechanism runs everywhere, all day, at smaller scale: a question goes to whoever owns that territory, an answer comes back, work proceeds. Nobody obstructs anything. An answer is simply a faster and better response to a question than an explanation is — so the reasoning stays where it started.

The low coupling that makes the team efficient is the same property that stops knowledge crossing between them. Clean ownership and knowledge concentration are one fact viewed from two angles.

We had reproduced, in six weeks and in miniature, the exact risk we had been commissioned to assess. That is what made the finding credible. We did not infer it from interviews. We walked into it ourselves, with every advantage and a fully committed expert on the other side.

The outcome.

The narrow question answered itself, and not through us.

By the end of the engagement, two developers were using the tooling on their own work, unsupervised, on their own subjects. One of them — whose day job is the modern web application — closed tickets in the thirty-year-old codebase. That crossing is the whole result. The method moved from the comfortable stack into the intimidating one, in the hands of someone who is not a specialist in it.

Which changes the shape of the succession problem entirely.

The assumption inside the company had always been that replacing the retiring engineer meant hiring a confirmed expert in a language almost nobody learns anymore. Rare, expensive, slow to train, and not something you grow from a small team in the time available. That assumption is why the problem had stayed open for years: it made it look unsolvable, so nobody started.

But if the tooling absorbs the punishing part — navigating hundreds of interdependent units, finding what touches what, reading three decades of accumulated decisions, and daring to change any of it — then what remains is domain knowledge. And domain knowledge is learned by working on problems, not by studying a language.

The successor does not need to be an expert in the old technology. They need enough technical judgment to assess what they read, curiosity about the domain, and a working relationship with the person who holds it.

That profile was already on the payroll.

So our central recommendation was organisational, not technical: stop asking the expert to document, and start bringing him problems.

Give someone the explicit job of carrying subjects to him, working through them alongside him, and writing down the why afterwards. He continues doing exactly what he enjoys, at full speed. The capture becomes a by-product, invisible from his side.

It works because the material already exists. His written replies during the engagement contained, unprompted and in detail, precisely the knowledge everyone was hunting for — why one model of a deadline is wrong, why an old optimisation exists, which convention preserves consistency downstream. He was already writing it down. What was missing was someone whose job it was to ask.

Two conditions decide whether it takes: frame the role as help with his work rather than preparation for his succession, and choose the person for the working relationship, not the seniority.

We also wrote down what had not been achieved. The feature was partially delivered — the core logic done, isolated and tested; the integration unfinished; and, most importantly, never validated against an independent source of truth. Of the five design defects, one was fixed during the engagement and four were documented as a target path for whoever picks it up.

A report that only contains good news isn't a report. It's marketing.

The real conclusion: the value of these tools here was not writing code faster. It was making a succession possible that, two years earlier, wasn't.

Engagement.

Open Lead. A scoped assessment that ended in a recommendation for embedded technical leadership — the kind of work where the deliverable is a decision, not a repository.

What we recommended is the shape Open Lead exists for: a part-time technical lead, two days a week, six months. Long enough to install practices, short enough not to create a dependency.

And explicitly not the same role as the internal successor. Those are two different jobs: one changes how the team works, the other must change nothing at all about how the expert works, because his way is productive. One person cannot hold both, and conflating them is how these arrangements fail.

The mandate is not tooling. Version control, CI and tests are the door, not the room. What is actually at stake is code review, release management, how work gets divided, how people collaborate day to day — plus the architecture decisions that need someone with no attachment to the existing system.

Because what was missing internally was never competence. This team picked up every modern practice they were shown, quickly and with appetite. The gap is not capability, it is exposure — and nobody there had the explicit mandate to change how the team works, or the standing to push it through where it met decades of habit.

That standing isn't granted by an org chart. It is earned by technical credibility a team recognises — and by going first. An outsider mandated for it can bring that at no internal political cost.

See how Open Lead works →

Got a similar problem?

Every module has an owner who knows it cold. Nobody has a second. The documentation project keeps not happening, and everyone can already name the person whose departure would hurt most. We've been in that room.

Let's talk

Lean builders. We deliver.