semantic state surface

situation

  • route showed a remote process; success view clear, surrounding states grew independently
  • spinner in one branch, raw error in another, empty-looking panel on denied access, plausible placeholder values while the authoritative response was absent
  • two facts looked identical: "nothing exists" vs "the screen does not know"
  • a transient request failure could look like an operation completed

why

  • an interface that fills gaps with plausible content is lying with good visuals: absence, denial, failure all look like ready data
  • invariant: every visible claim comes from the authoritative response or is labeled as uncertainty
  • mapping typed remote states to a small set of semantic primitives makes each condition a distinct, auditable surface instead of per-branch improvisation

invariants

  • every visible claim must come from the authoritative response or be clearly identified as uncertainty
  • each failure surface must name the next meaningful action: retry, correct, request access, wait, or stop
  • a screen must not manufacture content to preserve visual polish
  • exact time and state remain available even when a compact relative label is displayed

decision process

candidatereasoningdecision
keep one success component and add conditional text around itfast initially, but each new failure branch duplicates layout and loses semantic consistency.rejected
fill unavailable sections with plausible sample valueslooks complete in a screenshot but falsely asserts that the system has data or progress.rejected
show the raw transport exceptionpreserves a cause but hands provider vocabulary to the person without telling them what action is valid.rejected
map typed remote states to a small set of semantic state primitivesseparates authority from presentation, keeps actions bounded, and gives every route the same audit surface.selected

resulting shape

  • the query hook returns the remote state and typed failure category
  • the route or display component maps it once:
remote factsemantic surfaceperson can conclude
request pendingloadingthe system is still determining the answer.
successful empty responseemptythere is currently no matching record.
authorization failureblockedaccess or identity must be corrected.
retryable dependency failurerecoverable failurethe request did not complete; retry may be useful.
invalid input or configurationcorrection requireda specific prerequisite must change.
successful populated responsereadythe displayed facts are authoritative for the response timestamp.
  • the state primitive owns wording, iconography, action placement
  • the domain component supplies the semantic category and recovery action; never passes raw class strings or transport labels through its API

what this prevented

  • earlier shape allowed two regressions: fresh mount briefly showed old-looking sample content; denied response rendered as a blank section
  • selected design makes both impossible to hide: absence is explicit, denial distinct from emptiness, retryable failure cannot masquerade as ready data

verification matrix

use a controlled response or fixture for each state. for every render, verify the visible claim, action, and metadata together:

  1. pending preserves enough structure to avoid layout deception but claims no result
  2. empty states explain absence without an error treatment
  3. blocked states give an access-oriented action and no retry promise
  4. recoverable failures preserve a safe diagnostic category and expose retry only when it is valid
  5. ready states render only response-backed values and expose their exact timestamp in accessible metadata

good and bad

bad

return <WorkflowList items={query.data ?? sampleWorkflows} />;
  • the page turns missing authority into fabricated ready content
  • absence, denial, transient failure all look identical to success
  • visitor acts on facts nobody established; a screenshot review can never catch the lie because the screen looks complete

good

return query.isPending ? <WorkflowListSkeleton /> : <WorkflowListState query={query} />;
  • each remote condition renders its own truthful semantic state
  • pending, empty, blocked, recoverable failure become distinct auditable surfaces with bounded actions
  • the same primitive set is reused across routes instead of re-improvised per branch

search pages

go to any page