skip to content

Deterministic Assertions

Assertions that hold when timing does not: a settled invariant rather than a passing intermediate state, and no claim on an interleaving nobody promised. Interviewers probe promise versus coincidence.

on this pageshow

questions

3

Which property should an automated test assert on when the effect it checks lands only after the call returns?

level: juniorimportance: must knowfreq 58%

answer

  1. Ask what stays true afterwards
  2. The instant you looked matters
  3. Pending counts move while work runs
  4. Terminal facts versus in-flight facts

basics

~20 s

Assert on a settled invariant, a property that stays true once the flow has finished, such as a terminal status or a final total. Do not assert on a counter or an intermediate status that is true for only a moment.

solid answer

~40 s

Split the facts a case could check into two kinds. A **transient** fact is true only while the work is in flight, such as a pending count, an intermediate status or the depth of a backlog, so asserting on it makes the verdict depend on the instant you looked. A **settled invariant** stays true from the moment the flow completes onward, whatever route the work took: the request's terminal status, the final total, the fact that exactly one charge exists for a given identifier. Write the assertion against the settled invariant and phrase it as an end state rather than a step count. If nothing settled is observable, that is a design gap rather than a puzzle for the case, and the honest fix is to add a visible completion point.

code

pseudocode · 8 lines
pseudocode
# transient - true only during processing, so the verdict depends on timing
assert pending_count(orderId) == 1
assert order_status(orderId) == "AWAITING_PAYMENT"

# settled - true from completion onward, whatever route the work took
assert order_status(orderId) == "COMPLETED"
assert order_total(orderId) == 4000
assert charge_count(orderId) == 1

go deeper

for a junior

Be ready to say what your assertion is checking and whether that fact can change a second later. Name one property that stays true once the flow has finished, and contrast it with a count that moves while the work is still in progress.

for a middle

Explain the mechanics: which states in the flow have no outgoing transitions, why an in-flight value makes the verdict depend on the instant of observation, and how you would assert on the absence of an effect without racing it.

for a senior

Show that you have debugged this in a live system. Talk about a case that passed for months on an intermediate value, what changed underneath it, and how you rewrote the assertion around a fact the contract actually keeps.

for a principal

Own the standard: what teams are allowed to assert on for deferred work, which observable end states a service must expose to be testable at all, and how you stop assertion targets being chosen by whatever field happened to be reachable.

## The two kinds of fact a deferred flow exposes When a call returns before the work it started has finished, the system moves through a series of observable conditions, and they are not all the same kind of thing. A **transient** fact is true for a window and then stops being true: it describes where the work has got to. A **settled invariant** is a property that, once the flow completes, nothing in the design moves again for that unit of work: it describes what the work produced. A case is deterministic only if the fact it chose to check is of the second kind. No amount of care elsewhere rescues an assertion pointed at the first. Transient facts, all of which look perfectly assertable in a passing run: - a count of items awaiting processing for a given identifier - an intermediate status such as `SUBMITTED`, `RESERVED` or `IN_PROGRESS` - the depth of a backlog, or the number of handlers currently running - a field a later step overwrites, such as a `lastAttemptedAt` timestamp - a scratch record a cleanup step deletes once the flow finishes Settled invariants for the same flow: - a terminal status, meaning one the flow's state machine has no transition out of - a final total, balance or computed result the contract calls final - the exact number of records produced for one identifier, often the strongest available claim - the existence of a record whose creation is one-way - the absence of a record the contract forbids this flow from producing ## Why a transient assertion is not merely "sometimes right" The failure mode is worth stating precisely. An assertion on an intermediate status is not a correct assertion that occasionally loses a race. It is a claim about **the instant of observation**, and the instant of observation is not something the case controls or specifies. The case reads "is this request still in progress?" and the honest answer depends on how fast the machine was, what else was running, and whether a step happened to be batched with another. When it passes, it has proved nothing about the product, only that the reader arrived inside the window. When it fails, there is no defect to find. That is also why enlarging the window is not the repair. A bigger window changes the odds without changing what the case claims. Changing the assertion target changes what the case claims, which is the only move that makes the verdict mean something. ## Picking the invariant: three questions 1. **What is the last thing this flow does for this unit of work?** Follow the flow to its end and name the condition that holds there. If it ends by writing a terminal status, that status is your anchor. 2. **What could still change it?** If a later step, a scheduled sweep, a compensating action or the product's own redelivery path can move the value, it is not settled: it is merely slow. Settled is a claim about the design, not about how long a value has sat still. 3. **Can the case observe it exactly?** Prefer exact facts over approximate ones. "Exactly one charge exists for this identifier" is both stronger and more stable than "at least one charge exists", and it catches duplicates for free. ## A worked example Suppose a submitted order triggers a reservation, a charge and a stored receipt, and the call returns as soon as the order is accepted. | Fact the case could assert | Kind | Why | | --- | --- | --- | | The order's status is `ACCEPTED` | Transient | A later step moves it onward | | Two items sit in the pending list | Transient | Depends entirely on when the case looked | | The order's status is `COMPLETED` | Settled | The state machine leaves this state for no reason | | The recorded total is 4000 | Settled | Final once the charge is captured | | Exactly one charge exists for the order | Settled | The count is fixed once the flow ends | | A receipt exists and no second one does | Settled | Creation is one-way and the count is bounded | The first two rows are the ones a hurried author reaches for, precisely because they are the first values that become visible when the call returns. ## When nothing settled is observable Sometimes you look for an anchor and there is nothing to hold: the flow leaves no terminal marker, exposes no final total, and the only visible movement is an internal counter. That is a finding about the design, not a puzzle for the case to solve. A flow whose completion is invisible cannot be verified honestly by anyone, including the person who has to answer "did it actually work?" while the system is live. Raise it and get a settled observable added. A case written against the counter in the meantime is worse than no case at all, because it will be believed. ## What the discipline buys Assertions anchored on settled invariants survive the changes that break everything else: a step becoming faster or slower, work getting batched, an extra path being added, processing moving to a different unit of parallelism. They also review better, because a reader can check the claim against the contract instead of against the author's memory of one passing run.

  • How do you tell whether a property is genuinely settled or merely slow to change?
    Ask what the design promises, not what you observed. A property is settled when the contract says no further processing may change it: a terminal status with no outgoing transition, a total that is final once posted. A property that is merely slow to change still has later transitions in its own state machine, so asserting on it means racing a step you did not model. Read the state machine and pick a state the flow never leaves.
  • Your case must prove that no second charge was created. How do you assert on the absence of an effect that has not arrived yet?
    Absence is not settled until something else is. Anchor it: reach a settled invariant the design says comes after the effect you are ruling out, then assert the count is still one. Checking "not present" immediately after the call proves only that it had not arrived by then. Where no such anchor exists, the case cannot honestly prove absence and should be reduced to what it can prove.

A parcel's tracking page shows "out for delivery" for a while and "delivered" forever. Only one of those two facts is safe to check tomorrow.

saying these in an interview costs you the question

  • Asserts on a pending count and calls the result deterministic
  • Treats any value the system exposes as a valid assertion target
  • Assumes a status observed once will still be there later
  • Fixes a timing failure by lengthening the pause, not by changing the target
  • Believes an intermediate status is stable because it passed locally
open as a page

An automated case asserts two deferred effects landed in a fixed order. When is that assertion illegitimate, and what replaces it?

level: middleimportance: should knowfreq 45%

basics

~20 s

An ordered assertion is illegitimate whenever the design promises only that both effects happen, not the order they arrive in. Replace it with an unordered check: assert the set of effects, and assert sequence only where the contract states one.

open as a page

A passing run cannot show whether a behaviour is guaranteed or incidental. How do you decide which one you are asserting on?

level: seniorimportance: nice to knowfreq 26%

basics

~20 s

Green proves only that the behaviour held once. Check the contract, the interface's stated promises and the state machine, and ask whether anything forbids the opposite. If nothing does, the behaviour is incidental and the case should not assert on it.

open as a page