Every architecture model has the same weakness: it says what people believe the system looks like. A model maintained carefully through pull requests (Part 4) is far better than a folder of pictures, but it is still a statement of intent. The running system may disagree. A team adds a direct database read to fix an incident at two in the morning. An old integration nobody remembered is still called once a month. A queue is created in the console and never written into code.
There are now several sources that can describe what is actually there: the infrastructure code, the cloud provider's inventory of resources, and distributed traces of real requests. Each can produce a diagram. Our view is that these discovered diagrams are excellent evidence of what exists and poor evidence of what was meant, and that the value comes from comparing them with the intended model element by element, not from replacing it.
Living architecture documentation without pretending it is automatic set out what code can and cannot tell you, and the two rhythms that keep documentation alive. This part is about the mechanics: how each source works, how to match its output to a model, and where it will mislead you.
Mopane Medical Scheme is fictional, and its systems and figures are illustrative. Mopane runs its claims engine, member registry and provider portal on a managed container platform in one cloud region, defined mostly in Terraform. The data warehouse and some older integrations were set up by hand before the infrastructure code existed.
Three sources of discovered architecture
Infrastructure as code. Terraform's terraform graph command outputs the dependency graph of a configuration or plan in the DOT language, which Graphviz renders into a picture. It shows resources and data blocks and how they depend on each other. It is precise about what the code declares and silent about everything the code does not manage, which at Mopane included the warehouse. Infrastructure as code: why you need it and how to start small explains why that gap is common in organisations that adopted IaC part of the way through.
The cloud inventory. Every major cloud keeps a queryable inventory of deployed resources, such as Azure Resource Graph or AWS Config. This covers what the code missed, including resources created by hand. It is also the noisiest source: every network interface, disk, role assignment and diagnostic setting is a resource.
Traces. Distributed tracing records real requests as they cross services. Tools that build service graphs from traces pair the two sides of each call. Grafana Tempo's documentation, checked on 28 October 2026, describes pairing a client span with a server span for direct calls, a producer with a consumer for messaging, and a client span with database attributes for database calls, then recording each pair as an edge. This is the only one of the three sources that shows calls that actually happened, rather than resources that exist.
Each source sees a different slice. Infrastructure code sees intent expressed as code. The inventory sees what exists. Traces see what talks to what. None of them sees ownership, purpose or boundaries.
Reconcile by identity, not by eye
Putting a generated diagram next to the intended one and looking for differences does not scale past a few dozen elements. Reconciliation needs the same thing the model itself needs: stable identity (Part 2).
Mopane made the link explicit in three places:
- Resource tags. Every cloud resource that implements a model element carries a tag with the model identifier, such as
arch-id=claimsEngine. Terraform modules set it by default. The inventory query groups resources by that tag. - Service names in telemetry. The
service.nameattribute that each service reports in its traces is set to the model identifier. The service graph's nodes then line up with the model's containers without a mapping table. - A small mapping file for the exceptions: the hand-built warehouse, a pharmacy switching provider known only by its host name, and a legacy batch job.
With identity in place, a nightly job compares the discovered model with the intended model and sorts every element and relationship into one of four buckets:
| Bucket | Meaning | What happens |
|---|---|---|
| Match | Both agree | Mark the element observed, with the date |
| Drift | Exists in reality, not in the model | Raised to the owning team: add it, or remove it |
| Unbuilt | In the model, not found in reality | Check: still proposed, retired, or wrong |
| Mismatch | Same identifier, different properties | For example, a relationship that is asynchronous in the model but synchronous in traces |
The first run at Mopane found what first runs usually find. Two relationships existed only in reality, one of them the provider portal reading the member registry directly, added during an incident and never reviewed. One element existed only in the model: an "eligibility cache" proposed a year earlier and never built. Both went to people, not to an automatic fix.
Where generated diagrams mislead
Generated diagrams look authoritative, which makes their failure modes easy to miss.
Noise. A full inventory of a modest cloud estate contains hundreds of resources, most of which no architecture reader cares about. A generated diagram of all of them is accurate and unreadable. Filter to the question being asked, usually by resource type and tag, before rendering anything.
Missing intent. Discovery shows the current state. It cannot show the target state or say whether a component is meant to be there. The direct registry read at Mopane appeared in the service graph looking exactly as legitimate as the designed path through the claims engine.
No boundaries. Trust zones, data classification and team ownership are not resources. A generated diagram has no idea that the member registry holds health information or that the provider portal faces the internet. Those boundaries must come from the intended model.
Phantoms and gaps in traces. When a call reaches a service that is not instrumented, or arrives from one, trace-based service graphs create virtual nodes from peer attributes, or label the caller simply as a user. Tempo's documentation also notes that pairing becomes unreliable when the spans of one trace are spread across several processing instances, and that sampling makes raw request counts understate traffic. A node on a service graph is therefore an observation with conditions, not a confirmed component. A missing edge may only mean the call was not sampled during the window.
Point-in-time snapshots. A monthly batch job will not appear in a week of traces. Choose the observation window to match the slowest important rhythm, or treat absence from traces as weak evidence.
Combining both
The pattern that works is to keep the intended model as the authority for meaning and let discovery supply evidence.
- Discovery updates support levels, not structure. When a relationship in the model is seen in traces, its support level becomes observed with a date. When it is not seen for a full observation window, it is flagged for review, not deleted.
- Drift becomes a pull request, raised by a person. The nightly job opens an issue for the owning team. If the drift is legitimate, the team adds it to the model through the normal review. If it is not, the code or the resource changes.
- Generated views are labelled as generated. A view rendered from the inventory says so in its title, with the date and the query that produced it, so nobody mistakes it for the reviewed architecture.
Mopane replaced the non-blocking "did you update the model?" reminder from Part 4 with the drift report. It is more precise, because it names the actual new relationship rather than guessing from which files changed.
Keep it proportionate
Full reconciliation across three sources is a real investment, and not every organisation needs it at once. A practical order:
- Tag resources with model identifiers in the infrastructure code, which is nearly free once decided.
- Align telemetry service names with model identifiers.
- Run an inventory comparison monthly, then weekly.
- Add trace-based relationship comparison once tracing covers the main paths.
Each step is useful on its own. Together they turn "is the diagram still true?" from a meeting into a report.
Next: Part 6, Letting AI agents draw the architecture. All parts are on the series page.
How CloudNala can help
We help teams connect their architecture models to the evidence they already have: tagging conventions, telemetry naming, inventory queries and a reconciliation report that sends drift to the right owners. We can also run a one-off comparison of an intended architecture against what is deployed, as part of an architecture review or technology health check.
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.
Request an Architecture Review or write to us at consult@cloudnala.co.za