Most revenue in South Africa runs through systems nobody currently at the company fully understands. A core banking platform assembled over twenty-five years. A provincial health system built by three different vendors under three different administrations. A billing engine that survived two mergers and a name change. This isn't a failure of any particular organisation — it's what happens to any system valuable enough to keep running for a decade or more.
This is Part 2 of our series drawing on Chris Ford's O'Reilly Early Release book Agentic Engineering at Scale, applied to South African modernisation work. Part 1 introduced the harness framework — Guides, Guards, Checks and Sensors. This piece is about the hardest place to build one: a legacy system where almost none of that structure survived the years.
"Coding agents don't work on our old codebase"
We hear a version of this often, usually from a client who tried pointing a coding agent at a decades-old monolith and watched it lose the plot. It's a fair observation about naive use, and a misleading conclusion about the technology.
Ford's book puts a name to what actually happens: context rot. A coding agent's decision-making degrades as its context window fills — noticeably, well before the window is technically full. Point an agent at a ten-million-line codebase and ask it to "understand" or rewrite the whole thing, and it thrashes between fragments without ever building a durable model of the system, for the same reason a person handed the entire codebase printed out and told "read this, then explain it" would struggle. The problem isn't capability. It's that nobody gave the agent a way to be selective about what mattered.
The fix isn't a bigger context window. It's progressive context disclosure — giving an agent a structured way to load only the part of the system relevant to the question in front of it, the same way a senior architect moving between an enterprise capability map and a single function doesn't try to hold both in their head at once. Gregor Hohpe's metaphor of the architecture elevator captures this well: people move fluidly between floors of abstraction. Coding agents, left unaided, do not — you have to build them a lift.
Reverse engineering is not archaeology for its own sake
The purpose of reverse engineering a legacy system isn't to fully document it. A complete specification of a system is, by definition, the system itself — reproducing that would defeat the point of modernising it at all. The purpose is to produce a model that's faithful in the properties that matter, deliberately loose everywhere else, and actionable enough to guide the replacement.
That's a genuinely different exercise from "documenting the old system," and it changes what you're looking for. You're not trying to capture everything. You're trying to work out which behaviours are load-bearing — the ones a customer, an auditor or a regulator would notice if they silently changed — and which are accidental scar tissue nobody would miss.
Three sources of evidence matter, and they don't agree as often as you'd hope:
Code is direct evidence — it's mechanically what produces the system's actual behaviour. It's also not the whole truth: large legacy systems carry plenty of code that no longer materially affects anything.
Documentation is circumstantial evidence. It tells you what some human believed the system did, or was meant to do, at some point in the past. It's genuinely useful — especially for surfacing vocabulary, intent and the "why" behind a decision that code alone can't express — but it drifts, and it should never be treated as ground truth on its own.
Runtime evidence — change-data capture, observability, and real user-interaction logs — tells you what the system actually does in production, independent of what anyone believes or wrote down. It has its own blind spot: it's sample-based. A rare but business-critical annual reconciliation process might simply never show up in three months of logs. Absence of evidence in your telemetry is not evidence of absence in the business process.
Triangulating across all three — where they agree, confidence goes up; where they disagree, you've found drift, an abandoned assumption, or a gap in your own model worth chasing down — is what turns "we think it does X" into something you can actually build against.
Working in thin slices, not one big rewrite
A legacy estate large enough to deserve the name is too large to tackle in one pass, with or without agents. The book's acronym for a well-chosen unit of modernisation is LIFT: Limited enough to modernise without dragging in the whole estate, Instructive enough to teach the team something about the larger system, Fruitful enough to justify the effort on its own, and Transferable — the lessons carry into the next slice.
This is where the well-worn OODA loop (observe, orient, decide, act) earns its place as a schema for modernisation, because it maps cleanly onto where agents genuinely help and where they shouldn't be making the call alone:
- Observe — agents are excellent investigative assistants here, cutting the cost of searching and comprehending code, documentation and observability data. This is useful even if the rest of the modernisation stays conventional.
- Orient — agents can nominate candidate thin slices: seams, bounded responsibilities, coupling patterns. They shouldn't be trusted to choose the site of extraction unassisted — that's an investment decision as much as a technical one, involving organisational timing and business judgement that doesn't live inside the codebase.
- Decide — agents help assemble the specification: not one model, but several complementary ones (a state machine for a payment lifecycle, a contract for an integration point, an invariant for a business rule that must never be violated).
- Act — forward engineering from that specification, which is where Part 3 of this series picks up.
Making the model earn trust
A specification of the old system is only useful if you've actually tested whether it's right, and "right" isn't a binary. It has three dimensions worth checking separately: coverage — does it address what you actually care about; fidelity — is what it says accurate; and tolerance — how much gap is acceptable for this particular business purpose. A cheaper, more maintainable system with slightly simplified rules can beat an exact replica, if the business genuinely doesn't need the exact replica.
A few concrete techniques carry over well from software testing:
- Characterisation tests (from Michael Feathers's Working Effectively with Legacy Code) record the exact input and output of a piece of legacy behaviour, so you have a check — not a guess — for whether a change preserved it.
- Held-back validation evidence, borrowed from the train/test split in machine learning, stops your model from just memorising the cases you happened to look at while building it.
- Mutation testing logic, applied to a specification rather than code: deliberately vary the spec and see whether your available evidence is strong enough to reject the wrong variant. If it can't tell the difference, the spec is missing something that matters.
None of this removes the need for human judgement. Selecting where to extract, and deciding what "close enough" means for a given business process, still depends on people who understand the organisation — the agent's job is to make that judgement faster and better-informed, not to own it.
What this looks like in South Africa
We see three recurring patterns in local legacy estates that make this framing especially relevant: mainframe and AS/400 systems in banking and parastatals where the original developers have long since left; provincial and municipal systems assembled by a rotating cast of vendors with inconsistent documentation standards across administrations; and monolithic ERPs customised so heavily over a decade that the "customisation" is now most of the system.
In all three cases, the instinct to "just rewrite it properly this time" is understandable and usually wrong on its own — not because rewrites never work, but because a rewrite without a validated model of what must be preserved just moves the risk from "the old system might break" to "the new system might silently drop something nobody remembered mattered." Reverse engineering, done with the discipline above, is what closes that gap before you spend a single rand on the replacement.
How CloudNala can help
CloudNala builds the evidence base before we touch the roadmap — pulling together code, documentation and observability into a validated model of what your current system actually does, so modernisation decisions are made against reality, not institutional memory.
Work with CloudNala
CloudNala helps organisations move from technology ambition to practical execution across cloud, AI, data, platform engineering and digital services.
Whether you are exploring AI, modernising your cloud environment, building a public-sector digital service, or turning an idea into a working MVP, we can help you shape the roadmap and deliver the next step.
Map My Legacy Estate or write to us at consult@cloudnala.co.za