Appearance
Ticket metrics
gaia_ticket.metrics is a multi-value gaia_metric field carrying arbitrary named metrics {name, value, unit?, recorded?}. Its primary purpose is the success side of a ticket — how well it went — complementing the run footprint, which measures the cost side of a run (effort: tokens, duration, turns).
The field is generic — names are a convention, not a schema
The metric name is a free string (data), never a config allowed-values list, so a new metric kind needs no schema change. The names below are the canonical catalog: agreeing on them keeps metrics comparable and aggregatable across tickets. They are not enforced — a typo is simply a distinct metric — so treat this list as a shared vocabulary, and extend it when a new metric earns a home.
value is decimal(12,4), for exact aggregation across counts, ratios and hours. unit is a free label (ratio, h, count). recorded is an optional UNIX timestamp.
Omit empty keys, never send an explicit null
Leave recorded and unit out when they are empty — do not send an explicit null recorded over JSON:API. Drupal core's TimestampNormalizer returns a 500 on a null timestamp; an absent key is the correct shape.
Canonical metrics
| name | unit | meaning | who writes it | when |
|---|---|---|---|---|
ac_pass_rate | ratio | fraction of acceptance criteria passing in the review fresh run | agent (review) | at review, from the AC matrix |
review_bounces | count | number of review→coding loops before done | agent/conductor | incremented on each Not-OK bounce |
time_to_done_h | h | wall-clock hours from spec entry to done | conductor | at done |
rework_followups | count | follow-up bugs that reference this ticket after done | conductor/human | post-done, ongoing |
human_interventions | count | manual human corrections/edits per run on this ticket | conductor/human | during/after a run |
Write paths
- Agent or conductor (session scope): a JSON:API
PATCHofmetricson an in-scope ticket — allowed with no new permission, because a session write to an in-scope ticket already passesGaiaTicketAccessControlHandlerandmetricsfalls throughcheckFieldAccess. The field is multi-value, so a write is a read-modify-write union:GETthe current metrics, append, thenPATCHthe whole array — the same pattern aslinks. From an agent session the JSON:API call goes through thegaia dropshshell, which resolves its target from the connection config. - Human: the Metrics widget on the ticket edit form,
/admin/gaia/ticket/<id>/edit.
Reading and aggregating in Views
The gaia_metric Views handlers are keyed on the field type, so any gaia_metric field inherits them — gaia_ticket.metrics today, gaia_run.metrics later:
gaia_metricfield — renders one metric'svalue, pinned by ametric_nameoption, and is aggregatable (for exampleAVG).gaia_metric_valuesort —ORDER BYthe named metric's value.gaia_metric_valuefilter — a numeric filter on the named metric's value (for exampleac_pass_rate < 0.5), exposable.gaia_metric_namefilter — scope a view to one metric name before aggregating (presence or equality), exposable.
Not yet automated
- Derivation of these metrics — the conductor or agent actually computing and writing
ac_pass_rate,review_bouncesand friends at the right lifecycle point — is follow-up work. What ships today is the field, the write path, and the Views handlers. - A dashboard widget surfacing per-project success over time is an optional follow-up.
- Merging the run footprint into this model is reachable without rework, since the field type is reusable on
gaia_run, but is deliberately not done yet: the run footprint stays its own model for now.
Related
- How GAIA works — where runs, footprints and ticket state fit together.
- The normative spec — the TimeEntry and billing roll-up model that the cost side of a ticket uses.