Build1 publisher3 min readPublished
Three boxes, seven hops: a container diagram is not an incident map
A C4 container view of an EPCIS batch upload showed three services. One click actually fired seven independent executions, and nobody drew that until an incident forced the question.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- The C4 container diagram for the EPCIS batch upload flow in a system called ALSC showed three boxes: Upload API, Processing Service, and Notification Service.
- One upload triggers seven independent executions: browser request, Node.js Function, blob write, Service Bus message, .NET Function, Hangfire background job, and another Service Bus hop.
- C4's container level was built to answer what the deployable units are and how they relate structurally, not what actually runs, in what order, for one business action.
- C4 dynamic diagrams provide sequence-style views of a specific runtime scenario layered on top of the static container view, but on this project none was drawn until an incident forced the question.
- The container diagram gets maintained because it is the artifact everyone points to in design reviews; the dynamic view does not get the same attention because nothing forces it until something breaks.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A team working on a supply-chain system called ALSC found that its C4 container diagram for the EPCIS batch upload flow showed three boxes: Upload API, Processing Service, Notification Service [1]. One user click through that flow actually triggers seven independent executions: the browser request, a Node.js Function, a blob write, a Service Bus message, a .NET Function, a Hangfire background job, and another Service Bus hop [2]. The diagram accounted for three of them and hid four [14].
The gap is not a drawing error. C4's container level answers a structural question, which deployable units exist and how they relate, not the runtime question of what executes in what order for a single business action [3]. The framework has an answer for that too: dynamic diagrams, sequence-style views of a specific scenario layered on top of the static view [4]. According to the author, this project never drew one until an incident forced the question [4], and the reason is mundane. The container diagram gets maintained because it is the artifact everyone points at in design reviews; nothing forces the dynamic view to exist [5]. The author guesses most teams doing async, queue-heavy work are in the same position [6].
The incident cost was specific. A support ticket referencing one failed batch pulled in whichever four teams owned a piece of the chain, each grepping its own log store around a rough timestamp, hoping the clocks were close enough to match a batch ID by eye [7]. That is the operational shape of a diagram that models deployables: when the failure lands in the middle of a chain nobody has written down, the recovery procedure is a conference call and four text searches.
The fix was distributed tracing with OpenTelemetry [8], and the interesting detail is which hop turned that from nice-to-have into mandatory. Hangfire's Redis-backed queue does not carry request context by default, so a dequeued job has no idea which upload triggered it unless someone wires that link explicitly at the enqueue call [9]. Every other hop in the chain, the HTTP call and the Service Bus messages, has a natural place to carry a correlation ID [10]. That asymmetry is invisible on a container diagram, because the diagram never modelled the handoff in the first place [9][3]. It only surfaces when someone tries to follow one request end to end.
With the trace ID propagating across all seven hops, the same ticket resolves by pulling one ID and reading the actual path in Application Map; work that used to burn half a day takes as long as typing an ID into a search box [11].
The cost side is stated plainly in the source, which is worth noting because most tracing advice skips it. Trace volume maps directly to Application Insights ingestion cost, so blanket always-on tracing across every service, environment and request is a recurring line item [12]. The team's response was to build the ability to switch tracing on for one service during an investigation without a redeploy, rather than leave it running everywhere [13].
What to watch: whether the dynamic view survives now that the incident is closed [5]. Also worth checking in your own system is the queue technology, since the author's claim is that any container diagram stopping at services and their calls will undercount the real failure surface the moment a queue enters the picture [15]. The Hangfire case is the general pattern in miniature: the hop that carries no context by default is the hop your diagram is least likely to show [9].