Back to Blog
Strategy 8 min readJun 16, 2026

The Graceful Truth Layer: How We Taught Our API to Tell the Truth

We added a three-word field to every API response — state: "complete" | "partial" | "empty" — and it changed how the entire frontend reasons about data. Here is why this pattern matters.

Every API we built for SiteNexis used to return either data or an error. The data was whatever the database had. The error was whatever went wrong. This binary contract was fine for simple cases, but it broke down for the specific situation SiteNexis deals with constantly: the audit is running, some data exists, some does not, and the frontend needs to decide what to show. The binary contract gave the frontend no way to distinguish "no data because nothing happened" from "partial data because the crawl is still running." Both returned the same shape. The frontend had to guess.

The Three-State Model

The Graceful Truth Layer (GTL) wraps every audit API response in a standard envelope: a state field, a timestamp, and a data payload. The state field has three possible values. Complete means the audit finished and the data is a full, accurate result. Partial means either the audit is still running or the audit finished but some sub-component has not yet produced results — whatever data exists is valid but incomplete. Empty means no audit has run, the system is not configured, or the specific record does not exist. Each state has different UI semantics, and each is communicated explicitly rather than inferred.

  1. 1complete — audit finished, data is authoritative. Render the full dashboard with no caveats.
  2. 2partial — audit running or sub-score missing. Render what exists, mark it as in-progress, do not fabricate the rest.
  3. 3empty — no audit or not configured. Render an honest empty state with an action to generate real data.

What Changed in the Code

The implementation was deliberately narrow. The GTL is a response-layer pattern only. It does not touch the analyzers, the scoring logic, the database schema, or the agent orchestration. Every audit sub-report route now imports three functions: gtlResponse (wraps data with the appropriate state), gtlEmpty (returns the empty state with null data), and resolveGTLState (computes the correct state from audit status and data presence). The TanStack Query hooks that consume these responses unwrap the envelope and expose both the data and the gtlState to the component layer.

The GTL pattern returns HTTP 200 for all three states. The state field carries the semantic, not the HTTP status code. This allows frontend components to read the state without catching HTTP errors, which is the correct separation of concerns for a data availability signal versus a server error.

Why This Pattern Is Broadly Applicable

The GTL pattern is not specific to SiteNexis. Any system that produces data asynchronously, stores results in a database, and exposes those results through an API faces the same three-state problem. The audit is the job. The result is the output. The state is the contract between job completion and frontend rendering. Encoding that contract as a first-class field in the response envelope — rather than leaving the frontend to infer it from nulls, HTTP codes, and status strings — produces more honest UIs with fewer edge cases. It is the smallest possible change to the API layer that makes the biggest possible difference to the rendering layer.

Tags: API Design Backend Architecture GTL Data Contracts SaaS Engineering