research28 min studyLesson 975 in Engineering

Attach temporal obligations to stable logical request identities

Specify every accepted request's terminal outcome, distinguish eventual resolution from success and deadlines, and avoid aggregate-progress loopholes.

On this page

What you’ll understand

  • Express a per-request eventual terminal-outcome requirement.
  • Separate at-most-once effects, terminal consistency, and eventual completion.
  • Explain why identifier reuse, vague acceptance, and missing clocks weaken lifecycle specifications.

An aggregate counter can increase forever while one request never finishes. A temporal service contract therefore needs a logical identity for each obligation and a precise definition of acceptance and terminal outcome. Retries should refer to the same obligation, while genuinely new work needs a distinct identity. Once these foundations are explicit, temporal logic can describe what must always hold, what must eventually happen, and which environmental assumptions support that promise.

Define the events that create and discharge an obligation

Acceptance should identify the boundary at which the service takes responsibility for a request, such as durable admission under the modeled contract. A received network packet or an HTTP connection need not cross that boundary. Record the request identity and immutable payload association at acceptance. Define terminal outcomes explicitly: success, rejection, failure, or cancellation may discharge different promises. 'Every accepted request eventually resolves' permits a failure response unless the contract separately requires success under additional conditions. A system that rejects everything can satisfy a weak resolution statement while failing its intended purpose.

Use stable logical identifiers across transport retries, and include a generation or sequence component when a caller starts new work. A reused user identifier cannot distinguish two separate operations. Keep enough history in the model to know that acceptance occurred and which terminal result belongs to that same obligation. If production garbage-collects deduplication records, represent the retention or identity-reuse rule where it affects the contract. Otherwise a proof relying on permanent identity memory may not describe the actual retry horizon.

∀r∈R: □(Accepted⁡(r)⇒◊Terminal⁡(r))\forall r\in\mathcal R:\ \Box\bigl(\operatorname{Accepted}(r)\Rightarrow\Diamond\operatorname{Terminal}(r)\bigr)
R is the declared logical-request identity domain. Accepted and Terminal are persistent history predicates for the same immutable request generation; □ means always and ◇ means eventually, possibly already true. The implication is a required temporal property, not a consequence of Next without suitable progress assumptions.↔ Scroll wide equations horizontally.

Safety and progress are separate parts of the lifecycle

At-most-once effects constrain how many successful state-changing effects one logical request can cause. Eventual resolution constrains whether its obligation can remain pending forever. Neither implies the other: executing twice and eventually replying violates the first, while doing nothing forever can preserve it. Terminal consistency adds another safety requirement, such as preventing the same request generation from being both committed and cancelled when those meanings are exclusive. A compensating action requires its own semantics; it is not generally equivalent to erasing a previously visible effect.

Aggregate statements such as 'some request eventually completes' can be true while a particular accepted request starves. Quantify over each identity and inspect whether fairness applies to the relevant action instance. A bounded identity model can also hide starvation if an identifier is recycled and its old obligation disappears. If an infinite-request service is analyzed using a finite abstraction, justify how outstanding obligations are preserved. Monitor acceptance and terminal records using the same identifiers so implementation traces can be checked against the same lifecycle interpretation.

□(∀r: Neffect(r)≤1),□(∀r: ¬(Committed⁡(r)∧Cancelled⁡(r)))\Box\bigl(\forall r:\ N_{\rm effect}(r)\leq1\bigr),\qquad \Box\bigl(\forall r:\ \neg(\operatorname{Committed}(r)\land\operatorname{Cancelled}(r))\bigr)
The first formula bounds successful effects per logical request generation; counts are nonnegative integers. The second assumes commitment and cancellation are exclusive terminal meanings in this contract. These safety requirements do not imply eventual resolution or guarantee that compensation reverses an external effect.↔ Scroll wide equations horizontally.

A deadline needs time, not just a temporal operator

Eventually does not mean within five seconds, or within any fixed number of transitions. A deadline specification needs a modeled clock, an acceptance timestamp, and assumptions connecting clock advancement and execution to real time. Counting protocol steps is not a physical-time measurement when steps have variable durations. Clock skew, pauses, and unavailable dependencies can affect the claim. Separate a safety monitor that detects an exceeded deadline from a liveness assumption that the clock and service actually progress. A stopped clock can otherwise conceal indefinite delay in a naive model.

The queue instrument illustrates aggregate draining without identities. Reset, set λ=0 and μ=1, predict backlog one after three seconds, then take six Steps; predict backlog zero after one additional second and take two more Steps. Its starting backlog is four and each Step advances half a second. The fluid formula cannot say which of four logical requests remains outstanding, whether any particular request starves, or whether an effect was duplicated. This limitation is why per-request predicates and identity-preserving traces are necessary beside aggregate backlog metrics.

Seventy-five percent completion can hide an infinite obligation

Four logical requests A, B, C, and D are accepted. B, C, and D reach terminal outcomes, while A stays pending. The model permits an infinite stuttering suffix in that state and imposes no fairness that forces A's completion. Compare an aggregate 'eventually some completion' claim with the per-request property.

  1. The accepted set has size four, the terminal set has size three, and one obligation remains. The aggregate completion fraction is 3/4=75%.

  2. The statement that some accepted request eventually reaches a terminal outcome is true, because B, C, and D already provide witnesses. It says nothing about A's unfinished obligation.

  3. Along the explicitly allowed infinite stuttering suffix, Accepted(A) remains true and Terminal(A) never becomes true. The per-request eventual-resolution formula is therefore false for A, despite the aggregate completions.

The result

The infinite suffix is a lifecycle counterexample. A finite snapshot with one pending request alone would not establish eventual failure without that allowed continuation.

Explore the model

Interactive lab

Interactive lab · queue

A draining total cannot identify the remaining request

Reset, set λ=0 and μ=1, predict backlog 1 at t=3 s, then take six Steps. Predict backlog 0 at t=4 s and take two more Steps. This deterministic fluid backlog starts at 4 and carries no request identities, terminal statuses, duplicate-effect counts, or fairness assumptions. Its elapsed seconds belong to the toy formula, not a service deadline proof.

A draining total cannot identify the remaining requestFluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Current readings: Fluid backlog: 4; Net rate · λ − μ: −1 /s; M/M/1 mean residence: 1 s. All parameters are adjustable with the labeled controls below.02.557.51001.534.56Elapsed time · sFluid backlogλ < μ
Fluid backlogCurrent time
Fluid backlog
4
Net rate · λ − μ
−1 /s
M/M/1 mean residence
1 s
t = 0 s

Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forPer-request temporal promises need more state than an aggregate queue length.

Check your understanding

Which specification can distinguish one permanently pending accepted request from a system where other requests keep completing?

Try it yourself

A caller creates operations with sequence numbers seven and eight. Each should produce one effect. A faulty deduplication key uses only the caller identity, so operation eight receives operation seven's cached terminal result and produces no new effect. Count the intended and actual effects, and give a suitable identity shape.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Retries share a logical operation identity; new sequence numbers create different obligations.

Compare with the solution

The intended total is two effects, one for each operation; the faulty implementation produces only one. A key such as (caller identity, sequence number), with an immutable payload association and appropriate retention rules, distinguishes the obligations while allowing retries of each one to deduplicate. A terminal response for sequence seven cannot discharge sequence eight's promised operation.

Take it with you

  • Acceptance and terminal outcomes must refer to the same stable logical generation.
  • At-most-once effects, consistent terminals, and eventual resolution are independent requirements.
  • Aggregate progress and step counts cannot replace per-request liveness or real-time deadline assumptions.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.