Skip to content
Engine has no release yet: these pages describe unreleased main.

Service Objectives

What the engine promises about artifacts, as numbers an alarm can hold it to: publishing, serving a document, a frame becoming ready in a viewer’s browser, and the datastore’s verdicts. Each objective is declared once, in internal/objectives, with its reason; every recording site, the objective_burn alarm and the crewlet.objectives.events metric read the same constants, so a retune is one reviewed change rather than a drift between a panel and a pager.

Every objective is an event objective: over a thirty-day window, a target fraction of events must be good, and a good event is one answered without fault on the engine’s side within the objective’s bound. A latency percentile is the same shape stated the other way round: “p95 under 250 ms” is “95% of operations answered within 250 ms”. That is what lets a latency objective carry an error budget and a burn rate exactly like an availability one.

A client’s own refusal is an answer, not a fault: a publish refused because its base version moved, a quota, a policy finding or a malformed request is a good event; a 5xx, or an outcome nobody could establish, is a bad one.

ObjectiveMeasuresWhereGood eventWithinTarget
publish_successPublish successthe publish pipeline (internal/artifactupload), every create and publishpublished, or refused for the client’s own reason (a moved head, a quota, a policy, a bad request), excluding the upload transfer30 s99.9%
publish_appliedPublish latencythe publish pipeline, for a publish that moves no new bytes (a rollback, carries, edits)the domain’s decision to the record applied2 s95%
view_first_byteView time to first bytethe artifact origin (internal/artifactserve), every document requestthe first byte written, under any status but a 5xx300 ms99.9%
artifact_readyArtifact ready, reported by the viewer’s browserthe dashboard, through POST /artifacts/readythe frame’s ticket minted to the page’s bridge hello3 s99.5%
data_round_tripDatastore op round tripthe datastore writer (internal/artifactdata), every write and undoa verdict, not an unknown outcome250 ms95%
data_resolvedDatastore op resolutionthe datastore writer, every write and undoa verdict, not an unknown outcome5 s99.9%
change_visibilityChange visibilitythe stream push of a committed artifact or datastore changethe applier’s commit to the frame written to the socket1 s99%
wake_latencyWake latencythe changefeed, for a watch that fired or a mentionthe end of the debounce window to the woken turn’s start10 s95%
presence_joinPresence jointhe presence huba join to the first roster1 sbest effort, no budget
presence_cursorPresence cursorthe presence hub, across nodesa cursor frame to its delivery on another node150 msbest effort, no budget

A best-effort indicator has a bound and no budget: it is counted and exported, and it never burns. Presence is best effort by design, since it is told and never stored, and degrades silently.

ObjectiveRecorded byThe event
publish_successthe publish pipeline’s Create and Publish, whichever surface called them (the dashboard, an agent’s tool, the CLI)the request to its answer; the upload transfer is a separate request and is never counted
publish_appliedthe same, for a rollback and a publish whose files are all carried, restored, removed or editedthe domain’s decision to its record applied; a refusal is no latency event
view_first_bytethe artifact origin’s handler, for every request it answers as a document (a frame’s page, or a page the frame loads as one)the request to the instant the handler committed to its status
artifact_readyPOST /artifacts/ready, reported by the dashboard for every frame it opensthe frame handed to the dashboard to the page’s bridge hello, or to the frame failing
data_round_trip, data_resolvedthe datastore writer, for every write and undothe request to the verdict read back from this node’s rows; a write still pending on this node delivered no verdict and is a bad event

change_visibility, wake_latency, presence_join and presence_cursor are declared with their bounds and targets so that their recording sites (the stream’s push of a committed change, the wake of a fired watch or a mention, and the presence hub) borrow them rather than invent their own. An objective nothing records counts no events, exports no series and never burns.

An objective alarms when it spends its error budget faster than the month allows, judged over two windows at once. The burn rate of a window is its fraction of bad events divided by the objective’s budget (one minus its target): a burn rate of 1 spends exactly the month’s budget in a month.

PairLong windowShort windowFires atSpends
fast1 hour5 minutes14.4a fiftieth of the month’s budget every hour
slow6 hours30 minutes6a twentieth of the month’s budget every six hours

The long window says the burn is real; the short window says it is still happening, so objective_burn clears within minutes of the fault ending rather than an hour later. The long window must also hold at least two bad events: on a quiet node a single failure among a dozen requests is a burn of a hundred times the budget, and one failure is a fault report the request’s own log line already carries, not a rate.

The alarm names, for each burning objective, the fastest pair that fires and both windows’ burn rates. It is judged per node, like every alarm the engine raises, over the events that node measured; the crewlet.objectives.events counter, summed across the fleet by your collector, is the company’s figure. A self-hosted install gets the same constants as reference objectives.

Every server-side indicator reads an outage that keeps requests from reaching the engine at all (the artifact domain’s DNS or certificate, an edge, a corporate filter) as a quiet node. The ready report is the indicator that sees one: the dashboard reports, for every frame it opens, how long the frame took from its view ticket to the page’s bridge hello, through POST /artifacts/ready (see the API reference).

A report is held to what it could honestly have measured:

  • it names a live frame this deployment minted for the reporting credential, verified exactly as the artifact origin verifies the frame’s ticket, so no caller reports about a frame somebody else opened;
  • each frame reports once, and the node remembers a reported frame until its ticket ends (at most 65 536 at a time; past that a report waits for the earliest to end rather than being remembered loosely and counted twice);
  • no report is longer than the frame has existed;
  • one credential sends at most a sustained report a second, after a burst of thirty (a dashboard reopening every frame it had after a reconnect).

The node’s memory of reported frames is its own: a frame reported to two nodes is counted once on each, which the per-credential limit bounds. Each admitted report is recorded into crewlet.artifacts.ready.duration by its outcome and counted as one artifact_ready event.

Part of Crewlet. Generated from crewlet/crewlet main at ee70177.