Indicators

Indicators are named, reusable timeseries measurements backed by ConfitSQL queries. They surface across Agents, Issues, and Change Monitors, and live in a shared catalog that Firetiger maintains over time as your telemetry evolves.

Each Indicator is one of two kinds:

  • INDICATOR_KIND_RATIO — query produces time, good_events, total_events columns. Used for success-rate measurements (e.g. fraction of /checkout requests under 450ms).
  • INDICATOR_KIND_GAUGE — query produces time, value columns. Used for raw scalar measurements (e.g. queue depth, active organizations).

The query template references three reserved time-window placeholders that the service substitutes at compile time:

  • @start_time — inclusive query-window start
  • @end_time — exclusive query-window end
  • @resolution — bucket size

Service: firetiger.goals.v1.IndicatorsService and firetiger.goals.v1.IndicatorRelationsService

Resource name patterns:

  • indicators/{indicator} — the Indicator definition
  • indicators/{indicator}/activities/{activity} — append-only maintenance log
  • indicatorRelations/{relation} — attaches an Indicator to an Agent / Issue / Investigation

Access: Read-write

Example flow

Define an Indicator attached to an Agent, attach it to an Issue, then compile its query for charting.

1. Create an Indicator

curl -X POST "https://api.cloud.firetiger.com/firetiger.goals.v1.IndicatorsService/CreateIndicator" \
  -u "$USERNAME:$PASSWORD" \
  -H "Content-Type: application/json" \
  -d '{
    "indicator_id": "checkout-latency-p95",
    "indicator": {
      "display_name": "Checkout p95 latency under 450ms",
      "description": "Fraction of /checkout requests completing under 450ms.",
      "kind": "INDICATOR_KIND_RATIO",
      "unit": "%",
      "query": {
        "connections": ["connections/spans"],
        "confit_sql": "SELECT time_bucket(@resolution, span_start) AS time, count(*) FILTER (WHERE duration_ms < 450) AS good_events, count(*) AS total_events FROM spans WHERE span_start >= @start_time AND span_start < @end_time AND span_name = '\''/checkout'\'' GROUP BY 1",
        "description": "Reads from spans where span_name = '\''/checkout'\''. Latency from duration_ms."
      }
    },
    "initial_resource": "agents/checkout-flow"
  }'

CreateIndicator is atomic: on success the response carries the Indicator, the initial IndicatorRelation against initial_resource, and an initial IndicatorActivity ("Indicator created."). The server validates that confit_sql references all three reserved placeholders, then asks ConfitService.ValidateQuery to perform a schema-aware dry-run — the engine plans the query against in-memory empty parquet files derived from each touched table’s iceberg-declared schema (no data scan) — and confirms the planned output schema matches the kind contract.

2. Attach to an Issue

curl -X POST "https://api.cloud.firetiger.com/firetiger.goals.v1.IndicatorRelationsService/CreateIndicatorRelation" \
  -u "$USERNAME:$PASSWORD" \
  -H "Content-Type: application/json" \
  -d '{
    "indicator_relation": {
      "indicator": "indicators/checkout-latency-p95",
      "resource": "issues/FT-241"
    }
  }'

The backing table enforces uniqueness on (indicator, resource) for non-deleted relations. Re-attaching after a soft-delete is permitted.

3. Compile a chart query

curl -X POST "https://api.cloud.firetiger.com/firetiger.goals.v1.IndicatorsService/CompileIndicatorQuery" \
  -u "$USERNAME:$PASSWORD" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "indicators/checkout-latency-p95",
    "start_time": "2026-04-01T00:00:00Z",
    "end_time":   "2026-04-29T00:00:00Z",
    "resolution": "300s"
  }'

The response carries a ready-to-execute firetiger.query.v2.QueryRequest and the current Indicator metadata. Send the request directly to firetiger.query.v2.ConfitService.Query — result data does not proxy through the goals API.

Methods

IndicatorsService

Method Description
CreateIndicator Define a new Indicator and its first relation atomically
GetIndicator Retrieve an Indicator by name
BatchGetIndicators Retrieve multiple Indicators in one round trip
ListIndicators Enumerate Indicators in the catalog
UpdateIndicator Edit the Indicator definition (writes a maintenance-log activity)
DeleteIndicator Soft-delete (archive) an Indicator and its IndicatorRelations
UndeleteIndicator Restore a soft-deleted Indicator and its cascade-deleted relations
PurgeIndicators Hard-delete soft-deleted Indicators matching a filter
ListIndicatorActivities Read the maintenance log
CompileIndicatorQuery Compile a stored Indicator into a ready-to-execute Confit query
ReportIndicatorQueryError Flag a runtime query failure observed by a client so the indicator-fixer cron can repair it

IndicatorRelationsService

Method Description
CreateIndicatorRelation Attach an Indicator to a resource
ListIndicatorRelations Enumerate relations matching a filter
DeleteIndicatorRelation Detach (soft-delete) a relation

CreateIndicator

Define a new Indicator together with its first IndicatorRelation. Both writes plus an initial "Indicator created." activity land in one transaction.

POST /firetiger.goals.v1.IndicatorsService/CreateIndicator

REST alternative:

POST /v1/indicators
Field Type Required Description
indicator_id string No Caller-chosen kebab-case slug; if empty, the server generates one
indicator Indicator Yes The Indicator definition (see below)
initial_resource string Yes Resource the Indicator is initially attached to. Must match agents/{agent}, issues/{issue}, investigations/{investigation}, or monitoring-plans/{plan}

The indicator object accepts:

Field Type Required Description
display_name string Yes Human-readable label
description string No Markdown rendered as “What this measures” in the UI
kind enum Yes INDICATOR_KIND_RATIO or INDICATOR_KIND_GAUGE
query.connections string[] Yes Connection resource names the query reads from
query.confit_sql string Yes ConfitSQL template; must reference @start_time, @end_time, and @resolution
query.description string No Markdown rendered as “How this is grounded”
unit string No Display unit (%, ms, {jobs}, etc.)

GetIndicator

Retrieve a single Indicator including its query status (validation timestamp + last error).

POST /firetiger.goals.v1.IndicatorsService/GetIndicator

REST alternative:

GET /v1/{name=indicators/*}
Field Type Required Description
name string Yes Indicator resource name (e.g. indicators/checkout-latency-p95)

BatchGetIndicators

Retrieve several Indicators in a single request. Used after listing IndicatorRelations to hydrate Indicator details for each related resource.

POST /firetiger.goals.v1.IndicatorsService/BatchGetIndicators

REST alternative:

POST /v1/indicators:batchGet
Field Type Required Description
names string[] Yes Indicator resource names

Returns Indicators in the same order as names. A missing Indicator fails the entire batch with NOT_FOUND.


ListIndicators

Enumerate Indicators in the shared catalog. Supports AIP-160 filtering, AIP-158 pagination, and show_deleted to surface archived Indicators.

POST /firetiger.goals.v1.IndicatorsService/ListIndicators

REST alternative:

GET /v1/indicators
Field Type Required Description
filter string No AIP-160 filter (e.g. kind = "INDICATOR_KIND_RATIO")
order_by string No Sort order
page_size int No Maximum number of Indicators per page
page_token string No Pagination token from a previous response
show_deleted bool No Include soft-deleted Indicators

UpdateIndicator

Edit the live Indicator definition. There are no Indicator revisions in v1 — the definition mutates in place and an IndicatorActivity entry lands in the same transaction. Pass activity_description for human-authored maintenance notes; otherwise the service auto-generates a generic entry.

POST /firetiger.goals.v1.IndicatorsService/UpdateIndicator

REST alternative:

PATCH /v1/{indicator.name=indicators/*}
Field Type Required Description
indicator Indicator Yes New field values; only fields named in update_mask are written
update_mask FieldMask Yes List of paths to update (e.g. display_name,description)
activity_description string No Maintenance-log entry to write atomically with the update

Server-managed paths (name, etag, create_time, update_time, delete_time, query.status*) are silently filtered from the mask.


DeleteIndicator

Soft-delete the Indicator (sets delete_time) and cascade-soft-delete its IndicatorRelations using a shared delete_time. The shared timestamp lets UndeleteIndicator selectively restore only the relations the cascade touched — relations the user previously detached on their own carry a different delete_time and stay archived. A "Indicator archived." activity is written.

POST /firetiger.goals.v1.IndicatorsService/DeleteIndicator

REST alternative:

DELETE /v1/{name=indicators/*}
Field Type Required Description
name string Yes Indicator resource name

UndeleteIndicator

Restore a previously soft-deleted Indicator. Clears delete_time on the Indicator and cascade-restores any IndicatorRelations whose delete_time matches the Indicator’s (i.e. the ones DeleteIndicator archived together with it). Relations the user detached separately stay archived. An "Indicator restored." activity is written.

POST /firetiger.goals.v1.IndicatorsService/UndeleteIndicator

REST alternative:

POST /v1/{name=indicators/*}:undelete
Field Type Required Description
name string Yes Indicator resource name

The response carries the restored Indicator.


PurgeIndicators

Hard-delete soft-deleted Indicators matching an AIP-160 filter, along with their cascade-deleted IndicatorRelations and IndicatorActivities. Irreversible — typically driven by a retention cron rather than interactive use. Pass force=false for a dry-run that returns the count and a sample of names that would be purged without actually deleting anything.

POST /firetiger.goals.v1.IndicatorsService/PurgeIndicators

REST alternative:

POST /v1/indicators:purge
Field Type Required Description
filter string No AIP-160 filter against soft-deleted Indicators
force bool No When false (default), returns the dry-run count + sample without deleting

The response carries purge_count (number of Indicators that were/would be purged) and purge_sample (sample of Indicator names from that set).


ListIndicatorActivities

Read the maintenance log for an Indicator — creation, edits, archive, and (in future) re-grounding and dispute events. Activities are written by the service itself; there is no public CreateIndicatorActivity.

POST /firetiger.goals.v1.IndicatorsService/ListIndicatorActivities

REST alternative:

GET /v1/{parent=indicators/*}/activities
Field Type Required Description
parent string Yes Indicator resource name
filter string No AIP-160 filter
order_by string No Sort order. Default: create_time desc
page_size int No Maximum number of activities per page
page_token string No Pagination token
show_deleted bool No Include purged activities

CompileIndicatorQuery

Compile the stored Indicator into a ready-to-execute Confit QueryRequest. The service substitutes @start_time / @end_time / @resolution with typed SQL literals from the request and resolves query.connections into ConnectionConfig values. The client sends response.query_request directly to firetiger.query.v2.ConfitService.Query so result data does not proxy through the goals API server.

POST /firetiger.goals.v1.IndicatorsService/CompileIndicatorQuery

REST alternative:

POST /v1/{name=indicators/*}:compileQuery
Field Type Required Description
name string Yes Indicator resource name
start_time timestamp Yes Inclusive query-window start (substituted for @start_time)
end_time timestamp Yes Exclusive query-window end (substituted for @end_time)
resolution duration Yes Bucket size (substituted for @resolution)

ReportIndicatorQueryError

Flag that an Indicator’s query failed at runtime. The server persists the (truncated) error to query.status.error and bumps query.status.validate_time, so the indicator-fixer cron picks the Indicator up on its next pass and either auto-heals it (if a smoke-test against real data succeeds) or queues it for the indicator-curator agent to repair, replace, or delete. Idempotent: re-reporting the same error string still bumps validate_time but skips appending a new IndicatorActivity so a chart that errors on every page-load doesn’t spam the maintenance log.

Used by UI surfaces that execute compiled Indicator queries (e.g. the indicator detail chart, issue indicator cards) to surface live failures to the maintenance loop.

POST /firetiger.goals.v1.IndicatorsService/ReportIndicatorQueryError

REST alternative:

POST /v1/{name=indicators/*}:reportQueryError
Field Type Required Description
name string Yes Indicator resource name
error string Yes Runtime error observed by the client (e.g. DuckDB binder text, Confit error body). Truncated server-side; only a head slice is persisted to query.status.error. Empty values are rejected — clearing the status is the indicator-fixer cron’s responsibility, not a public client surface.

CreateIndicatorRelation

Attach an Indicator to a resource (Agent, Issue, Investigation, or Monitoring Plan). Idempotent against soft-deleted relations: re-creating one that was previously detached is permitted.

POST /firetiger.goals.v1.IndicatorRelationsService/CreateIndicatorRelation

REST alternative:

POST /v1/indicatorRelations
Field Type Required Description
indicator_relation.indicator string Yes Indicator resource name
indicator_relation.resource string Yes Target resource name (agents/..., issues/..., investigations/..., or monitoring-plans/...)

ListIndicatorRelations

Enumerate relations matching a filter. Typical reads filter by a single resource (Issue / Agent / Investigation / Monitoring Plan page) or a single indicator (Indicator dependents tab).

POST /firetiger.goals.v1.IndicatorRelationsService/ListIndicatorRelations

REST alternative:

GET /v1/indicatorRelations
Field Type Required Description
filter string No AIP-160 filter (e.g. resource = "issues/FT-241" or indicator = "indicators/checkout-latency-p95")
order_by string No Sort order
page_size int No Maximum number of relations per page
page_token string No Pagination token
show_deleted bool No Include detached relations

DeleteIndicatorRelation

Detach an Indicator from a resource (soft-delete). The Indicator itself is unaffected.

POST /firetiger.goals.v1.IndicatorRelationsService/DeleteIndicatorRelation

REST alternative:

DELETE /v1/{name=indicatorRelations/*}
Field Type Required Description
name string Yes IndicatorRelation resource name (e.g. indicatorRelations/rel-abc)

This site uses Just the Docs, a documentation theme for Jekyll.