Summary

  • RFC 5267 maintains a search or sort result as an initial answer plus position-sensitive ADDTO and REMOVEFROM updates associated with the original command tag; the standard expressly says there is no snapshot facility.
  • A result can still be returned when the server refuses live updates with NOUPDATE, and continuity ends on cancellation, mailbox deselection or an unaccounted transport gap. A responsive interface is not proof that the underlying context remains reconstructable.

The screen moved, so everyone assumed it was current

A live search is persuasive because it performs freshness. A new message enters the list without a refresh. A flag change removes another row. The count changes. The viewport remains calm. To a user, and often to the system around it, the moving list becomes “the current mailbox.”

RFC 5267 describes something more exact. A client sends SEARCH, UID SEARCH, SORT or UID SORT with the UPDATE return option. The server returns an initial result and may later send unsolicited ESEARCH responses carrying ADDTO and REMOVEFROM. Those changes refer back to the original command through its tag. They are instructions for maintaining one requested ordering, not independent observations that can be shuffled, deduplicated by appearance or applied to any similar query.

The standard is unusually direct about the limit: there is no snapshot facility. CONTEXT can hint that the server may benefit from caching or indexing a result, but the server may ignore that hint. Whether it caches internally must not alter its externally observable behaviour. The authority available to the client is therefore not “the server keeps a frozen view for me.” It is “I obtained a baseline and then received every valid patch for this active context.”

That distinction changes what an operator must prove. A screenshot proves that a list rendered. A current-looking count proves that some response reached the interface. Neither proves that the initial answer was complete, that UPDATE was accepted, that every intervening patch arrived, or that the context still belongs to the currently selected mailbox generation.

The result is a small replicated state machine

ADDTO and REMOVEFROM are not friendly event labels. They form a position-bearing patch language. ADDTO tells the client where ordered results must be inserted. REMOVEFROM tells it where ordered results must be removed. A context created by SEARCH or SORT uses message sequence numbers; a context created by UID SEARCH or UID SORT uses UIDs.

RFC 5267 requires the client to process these data items in the order in which they appear, including multiple items within one ESEARCH response. The server has the matching obligation to generate them so that this serial application preserves the requested result order. That requirement exists because the operations need not commute. Removing at one position and then inserting at another can yield a different list from applying the same two operations in reverse.

The minimum audit object is consequently a state machine: initial ordered membership, identifier mode, search program, requested sort order, original command tag, and a monotonically preserved receive sequence of patches. A table containing only “current member UIDs” loses how the state was reached. A log that gives every patch a local timestamp and later sorts by that clock may also corrupt the authority, because receive order—not wall-clock aesthetics—is the specified order.

The command tag is part of the identity. While an updating context is active, the client cannot reuse its tag for another such context; the server must reject the collision with BAD. This is not administrative tidiness. The tag is how unsolicited ESEARCH updates remain attributable to the exact search that created their meaning.

Sequence numbers make the wire order part of reality

UIDs give durable message identifiers within their defined scope. Message sequence numbers are positional and can change after expunge. RFC 5267 therefore imposes specific ordering around mailbox events.

When delivery or append causes an ADDTO that carries message sequence numbers, the server must send it after EXISTS, because only then are those new sequence numbers valid. When expunge causes a REMOVEFROM containing sequence numbers, the server must send it before EXPUNGE, while the old numbering still means what the removal instruction says it means.

This creates a single causal transcript. EXISTS, FETCH, ESEARCH updates and EXPUNGE cannot be captured into unrelated queues and reconciled later on the assumption that timestamps will restore the truth. The ESEARCH response may arrive while no command is running, during another command, or while the client is in IDLE. A recorder that watches only request-response pairs can miss precisely the unsolicited material that maintains the context.

There is a second sequence-number trap inside the query. If the search program itself contains message sequence numbers, those operands are evaluated when the command is received. Later renumbering of the referenced messages does not generate an update merely because their numbers changed. Re-evaluating the original numeric expression against a later mailbox would be a different search, not maintenance of the first one.

For production evidence, “we can replay the UI events” is too weak. The replay must preserve the protocol order, the identifier mode and the selected-mailbox generation in which each number was meaningful.

A valid initial result can arrive with no live promise

Servers may refuse to provide updates, for example when an internal context limit is reached. The protocol exposes that refusal as an untagged NO carrying the NOUPDATE response code and the affected command tag. Other return options must still be honoured.

This produces a dangerous, perfectly valid combination: the client receives useful search data and a successful completion, but it did not receive the continuing update service it requested. If the parser records the rows and drops the untagged refusal, the interface can present a live-looking list whose authority ended at creation.

The standard requires at least one updating context per client and recommends more. It also recognizes that sorted contexts can cost more than unsorted ones, so refusal of a sorted context does not prove that a search context would be refused. A client may retry with a less expensive query. What it cannot do is silently convert “initial answer plus refused update” into “current live result.”

The operational state model needs an explicit branch: requested, accepted, refused, active, cancelled, ended by deselection, or continuity unknown. “Loaded” is not enough.

A partial viewport does not bound the update stream

PARTIAL lets a client request a positional slice of an ordered result. That makes large searches usable: fetch the rows visible on screen, then request other windows as the user scrolls. But UPDATE does not interact with other return options. Combining UPDATE with PARTIAL does not limit updates to the displayed window. The client can receive changes for matching messages that currently lie outside its area of interest.

The same rule applies to MIN, MAX and COUNT. UPDATE reports changes to the matching set; it is not narrowed to the summary value requested beside it. An implementation that discards off-screen updates because “the user has not loaded that page” no longer maintains the context whose positions its next PARTIAL request will use.

This is where front-end architecture can accidentally rewrite protocol semantics. Virtualized lists encourage components to treat the viewport as the owned state and everything else as replaceable cache. RFC 5267 makes the maintained ordered result the authority surface. The viewport is only one projection of it. If the product chooses not to retain context-wide changes, it must invalidate and rebaseline rather than pretend the old positions remain trustworthy.

Continuity has explicit endings and silent ones

Updates stop when the mailbox is no longer selected or when the client issues CANCELUPDATE, whichever occurs first. CANCELUPDATE names contexts by the tags of the original commands, after which the server may free the resources. Reusing the same criteria later creates a new observation. It does not revive the old stream.

Disconnect is equally decisive even though the command is absent: the authenticated session and selected mailbox no longer exist. Parser failure, backpressure loss and a transport segment that cannot be accounted for are less graceful but have the same evidentiary consequence. Once one delta may be missing, later deltas do not prove the reconstructed list is current. A position-bearing stream cannot heal itself merely by continuing.

Another protocol may provide a resynchronization route. RFC 7162, for example, defines CONDSTORE and QRESYNC around modification sequences and known state. But adjacent capability is not automatic repair. The client must actually meet that protocol's prerequisites, execute it, verify the result and establish a new baseline. IDLE keeps a connection open for unsolicited responses; NOTIFY expresses event interests. Neither turns a broken CONTEXT transcript into a snapshot.

The safe default after an unexplained gap is unglamorous: mark the context discontinuous, stop authorizing decisions from it, and rerun the search.

Running code means preserving the patch, not the animation

Lu Heng's Running-Code Primacy gives a useful test. What is actually running? Not “live search” as a feature name. The running object is an exact search program, received under one capability set and mailbox selection, producing one baseline and a serialized series of tagged changes until a defined or detected boundary.

Reality-layer discipline separates the pieces that the interface compresses. The initial result is one observation. The server's acceptance of UPDATE is another. A received patch is evidence of one transition. The client's reconstructed list is a derived state. The visible page is a projection. A user's action—moving, deleting or escalating a message—is a further consequence. Smooth rendering cannot be promoted backward into proof of the earlier layers.

The abstraction remains safe only while it is reversible. Every inserted or removed row should be traceable to the context tag, identifier mode, receive position and causal mailbox sequence. Every claim of currentness should be traceable to an uninterrupted lifecycle or to a completed rebaseline. If the trace ends at a component state object or screenshot, the system has presentation, not authority.

Sources