skip to content

questions

3

How does an automated case use a correlation identifier it generated to prove an asynchronous flow reached every expected hop?

level: middleimportance: should knowfreq 52%

answer

  1. Prove the work happened, not just finished
  2. Tag the request with a per-run value
  3. Ask which steps recorded that value
  4. Poll until the expected hop set completes
  5. Name the missing hop in the failure

basics

~20 s

Generate a value unique to that run, send it with the triggering request, and let the flow carry it. Then poll for the step records written under that value and assert the expected set of hops appeared.

solid answer

~50 s

A correlation trail turns "did the work happen" into "which steps recorded themselves under my value". The case mints a value unique to this run - never a fixed constant - and attaches it to the triggering request so every participating step re-emits it. The assertion then names an **expected set of step markers** and polls the record store until that set is complete or the flow's settle window expires. Three details make it trustworthy. The value must be unique per case, or parallel runs read each other's evidence. The claim must be about the *set* of hops, not the order they were written, unless the design actually promises an order. And the expected list must come from the flow's contract rather than from a recording of one green run. When the window closes with hops missing, the case fails and names exactly which markers were absent.

code

pseudocode · 15 lines
pseudocode
correlation = "case-" + uniqueSuffix()
send(order_request, headers = { correlation_id: correlation })

expected = { "accepted", "priced", "reserved", "confirmed" }
deadline = now() + 30s

repeat until now() > deadline:
    seen = record_store.hops_for(correlation)
    if seen contains all of expected: break
    wait 500ms

if seen contains all of expected:
    pass
else:
    fail("hops never recorded: " + (expected - seen))

go deeper

for a junior

Be ready to say what a correlation value is: an identifier the case generates, sends with the request, and expects the flow to carry, so the run can find records of its own work afterwards.

for a middle

An interviewer expects the mechanics: minting a per-run value, attaching it to the trigger, polling the record store for markers carrying it, and asserting on the set of expected hops rather than on one final flag.

for a senior

Show judgement about how much the evidence is worth: which hops deserve an assertion, why a marker proves reach and not correctness, and how parallel runs are kept from reading each other's records.

for a principal

Own the tradeoff: how much of a flow the team commits to recording as verifiable step markers, what that instrumentation costs to keep accurate, and which verdicts you refuse to base on it.

## The problem a correlation trail solves When a request is handled asynchronously, the response returns before the work is finished. Once the flow settles, the case can read the final stored result - but that result is a single point. It says where the system ended up, not which steps got it there. Two different paths can leave the same end state: the intended one, and a shortened one where a step was skipped and a default filled in. A **correlation trail** closes that gap. The case mints a value unique to this run, sends it with the trigger, and relies on the system to carry that value along the flow so each participating step records a marker under it. The verdict becomes a question about a set: *did every step I expected record itself under my value, inside the time this flow is allowed to take?* Three terms, used precisely below: - **Correlation value** - a per-run identifier the case generates and attaches to the triggering request. - **Hop marker** - a record a step writes, carrying that value, once it has completed its own work. - **Record store** - whatever the run can query for those markers: a table, an indexed log, a recording service the run reads over its own interface. ## Building the assertion 1. **Mint a value unique to the run.** Something like `correlation = "case-" + uniqueSuffix()`. A constant reused across runs destroys the isolation the whole technique rests on. 2. **Attach it to the trigger** - a request field, a header, a queue message attribute. It has to be the value the system propagates onward, not one the case only keeps for itself. 3. **Name the expected hops explicitly.** `expected = {accepted, priced, reserved, confirmed}`. The list is derived from what the flow promises to do, and it changes deliberately when the design changes. 4. **Poll to a deadline.** Query for markers carrying the value until the expected set is complete or the settle window expires. Before the deadline, a missing hop is inconclusive; after it, a missing hop is a result. 5. **Fail with the difference.** `missing = expected - seen`. A failure naming the hop that never arrived is a defect report; a failure saying only "trail incomplete" is a puzzle for whoever picks it up. ## What each piece of evidence is actually worth | Evidence | What it proves | What it does not prove | |---|---|---| | The settled result | where the flow ended up | which path produced that end state | | A marker the step writes after its own work | that the step ran to completion | that its output was correct | | A marker written at the call site on dispatch | an attempt left the caller | that the receiving step handled it | | No marker for a step | nothing on its own | that the step was skipped | The middle two rows are where most candidates stop thinking. A hop marker is evidence of **reach**, not of correctness: a pricing step can record itself and still have computed the wrong price. That is why the trail complements assertions on the settled outcome rather than replacing them - the outcome check says the answer was right, the trail says the right path produced it. The bottom row matters even more and is treated on its own below. ## Ways this goes wrong - **A shared constant.** If every run tags its request with the same value, the query returns a pile of records from every run that ever executed, and a case can pass on hops another run wrote. Uniqueness is not hygiene here; it is the entire basis of the claim. - **Parallel bleed.** Suites run concurrently. Two cases exercising the same flow at the same time must be distinguishable by the value alone, or the assertion is reading a mixture. - **Reach read as correctness.** "All four hops present, therefore correct" is a common overclaim. It is present-and-reached, nothing more. - **An expected list captured from behaviour.** If the list of hops was recorded from a successful run rather than derived from the contract, it bakes in whatever happened to run that day and drifts silently with the code. - **A single read instead of a bounded poll.** One query fired immediately after the trigger measures the system's speed, not its behaviour, and produces failures that no defect caused. - **Asserting on hop timing.** Durations between markers vary with load. Unless the flow promises a bound, a case that asserts on them is asserting on the machine it ran on. ## Keeping the claim honest A trail-based assertion is only as strong as the records it reads. If a step writes no marker, its absence from the trail proves nothing at all, and a case that treats absence as a skip will raise defects against working code. The discipline is to assert only over hops that genuinely record themselves, to name in the case which segment of the flow that covers, and to add a marker to the product deliberately when a hop matters enough to be part of a verdict. Written that way, the trail answers a question no end-state assertion can: not just *did it end correctly*, but *did it get there the way we said it would*.

  • Why must the correlation value be unique to the run rather than a fixed constant?
    A constant makes every run's evidence indistinguishable. The query returns records written by earlier and concurrent runs, so a case can pass on hops it never caused, and a failure points at a pile rather than one flow. A per-run value scopes the evidence to work this case triggered and keeps parallel cases from reading each other.
  • Where should the list of expected hops come from?
    From what the flow is specified to do, not from a capture of one successful run. A recorded list bakes in whatever happened to execute that day, including incidental steps, and it quietly stops matching when behaviour drifts. Deriving it from the contract means a change to the flow forces a deliberate edit to the case rather than a silent divergence.

It is the difference between finding a parcel on your doorstep and reading its scan points: the doorstep proves it arrived, the scans prove which depots actually handled it.

saying these in an interview costs you the question

  • Reuses one fixed correlation value across every run
  • Treats a hop marker as proof the step was correct
  • Lets another run's records satisfy the assertion
  • Reads the trail once instead of polling to a deadline
  • Builds the expected hop list from one recorded run
open as a page

How do you catch a step that an asynchronous flow skipped in silence when the final stored record still looks correct?

level: seniorimportance: should knowfreq 44%

basics

~20 s

A final-record assertion sees only the last write, so a step whose effect never reaches that record can vanish. Assert instead on the marker each step writes after its own work, and fail when the expected set is incomplete.

open as a page

What may a case honestly assert when the correlation trail it checks covers only the hops that emit records?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

Only that the recorded hops were reached. Anything unrecorded is unknown, not proven absent and not proven correct. Scope the claim to the covered segment, verify uncovered steps by their effects, and say plainly which parts stay unverified.

open as a page