Measurable
Makes "we shipped it" and "we can see it" the same statement. A change is
only done when its impact is measurable and its regressions are visible —
this skill decides what telemetry a diff needs, writes or audits it, and
records a per-repo profile so the answer doesn't have to be re-derived
every time.
This SKILL.md is a thin index. Detailed rules live in rules/*.md
and load on demand. The profile template lives in templates/*.md.
Composes, does not duplicate. Frontend event design is
rum-tracking's job — this skill
only decides whether a user-facing change needs RUM and hands off to it.
Backend span/metric semantic conventions belong to the otel-instrumentation
and otel-semantic-conventions skills (from the
dash0 agent-skills repo) when
installed — invoked via Skill(), skipped silently otherwise, with
rules/backend-instrumentation.md as
the built-in fallback. Persistence for the Observability Profile is
persistent-memory's
project-shared tier — this skill never invents its own storage layer.
Mode Detection
Parse $1 as the mode.
State the detected mode in one line before continuing.
| Mode |
Default |
Trigger |
guide |
yes |
"is this measurable", "what telemetry do I need", default if no mode |
implement |
|
"add telemetry", "instrument this", "add RUM and API telemetry" |
audit |
|
"audit observability", "check observability coverage", "--diff", aw Phase 4 gate |
setup |
|
"set up observability profile", "first-time setup", "/measurable setup" |
If $1 is a diff, PR, file, or directory, treat it as the scope for
implement or audit.
Workflow by Mode
Guide mode (default)
The user is deciding whether and what telemetry a change needs.
- Load
rules/scope-detection.md and classify
the change: frontend (web), frontend (mobile), backend/API, infra, or
mixed. In a monorepo, check for a committed Observability Profile first
(see rules/setup-profile.md) so package
boundaries and stack choices don't have to be re-guessed.
- For a frontend classification, recommend the user-facing events per
rules/frontend-rum.md (thin pointer into
rum-tracking).
- For a backend/API classification, recommend the spans, metrics, and
structured logs per
rules/backend-instrumentation.md.
- Regardless of classification, name the specific regression signal —
the metric, alert, or dashboard panel that would turn red if this change
broke — per
rules/regression-signals.md.
"We added a log line" is not a regression signal; "P99 latency on
POST /checkout is now tracked and alerts at 2× baseline" is.
- Do not prescribe code yet — that's
implement mode. Guide mode ends with
a short, concrete list: signals to add, and why each one is the one that
would catch a regression.
Implement mode
The user (or the autonomous-workflow Phase 3 trigger) wants the
instrumentation written.
- Run the Guide-mode classification (Step 1 above) first — never write
telemetry code without first stating what kind of change this is.
- Frontend user-facing change → delegate:
Skill("rum-tracking", "implement", "<target>")
This skill does not re-implement event design; it only confirms the
delegation happened and that the resulting events map to a named
regression signal (Step 4 above).
- Backend/API change → follow
rules/backend-instrumentation.md:
a span per new/changed operation with OTel semantic-convention attributes,
a RED metric (rate, errors, duration) if the operation is on a hot path,
and a structured log at the point of failure. Prefer delegating to
Skill("otel-instrumentation") / Skill("otel-semantic-conventions")
when installed; the rule file is the fallback when they are not.
- Either path → apply
rules/regression-signals.md so errors
and warnings are never silent: span status set on failure, a log at
error/warn severity with enough context to triage without
reproducing, and — when the Observability Profile names an existing
dashboard or check rule for this package — a note that it now covers
the new path (never auto-edit dashboards/alerts; that's dash0's job
in Dash0 chat, not this skill's).
- Report what was added as a short "Observability" summary (one line per
signal, with file:line) —
autonomous-workflow Phase 6 folds this into
the PR walkthrough.
Audit mode
The user (or the autonomous-workflow Phase 4 gate) wants an existing diff
checked for coverage gaps, without writing anything.
- Walk
rules/audit-checklist.md against the
diff (or the target file/directory if no diff is given).
- Classify each finding:
missing (no signal at all for a changed path
that needs one), unlinked (a signal exists but maps to no regression
detector — Step 4 of Guide mode), or pass.
- Cite a file path and line number for every finding.
- Output a ranked list. Advisory by default —
missing and unlinked
findings are both reported, neither blocks. Pass --strict to make
missing findings on web/mobile/api/worker paths block the
caller's gate (unlinked stays advisory even in --strict, since not
every signal needs a bespoke dashboard on day one). This mirrors how
critical and optimize-approach ship non-blocking by default in this
registry — a brand-new coverage heuristic earns a hard gate only once a
team has opted in, not on day one.
- Never auto-edit in
audit mode — that is what implement mode is for.
Callers of audit mode. autonomous-workflow Phase 4 (its Observability Gate) and the
pr-reviewer agent's measurability lens (Step 2.4e, via
agents/shared/rules/measurability-review.md) are both audit-only consumers. autonomous-workflow
stays advisory unless a run opts into --observability-strict; the reviewer defaults to strict (a
repo opts down with measurable: advisory), because a merged change that ships a new failure mode with
no signal is the case the lens exists for. The reviewer additionally gates the call behind two
conditions of its own — the diff must touch a web/mobile/api/worker path and add or alter
observable behaviour — so a refactor PR never reaches this mode at all. Neither caller may invoke
implement: one is a gate, the other is read-only.
Setup mode
First-time (or repo-onboarding) interview that records durable project
facts so every later guide/implement/audit run stops re-deriving them.
- Follow
rules/setup-profile.md end to end:
interview, monorepo package map, write via persistent-memory
(project-shared tier), confirm.
- Re-run any time the stack changes or a new package is added —
setup is
idempotent and updates the existing profile rather than duplicating it.
Required Reading by Mode
Load on demand — do not preload.
Core Principles
- A signal without a regression detector is not coverage. Emitting a
span or a log is necessary but not sufficient — name what would alert or
what dashboard would show the break. Anti-pattern: "instrumented" meaning
only "some code now calls a tracer."
- RUM and API telemetry are two different jobs, not one. Frontend
product-analytics event design stays owned by
rum-tracking; this skill
decides whether a change needs it and folds it into the same coverage
picture as backend spans/metrics/logs.
- The Observability Profile is the source of truth for "how does this
repo do telemetry." Never re-guess the stack or the monorepo package
map when a profile exists; run
setup once, guide/audit read it after.
- Errors and warnings are first-class deliverables. A change that adds
a new failure mode without a way to see that failure mode in production
is incomplete, regardless of test coverage.
- Advisory on frontend/backend code, hands-off on Dash0 config. This
skill writes application-level instrumentation. It never creates or edits
dashboards, alerts, or SLOs directly — those are proposed through Dash0
chat (the
dash0 agent) so a human reviews and creates them there.
- Companions skip silently.
rum-tracking, otel-instrumentation,
otel-semantic-conventions, and persistent-memory are all optional —
degrade to the built-in rule files and say so in one line, never block.
Anti-patterns (one-liners)
- Calling a change "instrumented" because a log line was added, with no
metric or alert that would ever surface a regression.
- Re-deriving the monorepo package map or telemetry stack every run instead
of running
setup once and reading the profile.
- Writing frontend analytics events inline instead of delegating to
rum-tracking's centralized wrapper.
- Swallowing an error (
catch {}) without a log at error severity and a
span status flip.
- Editing a Dash0 dashboard or check rule directly from this skill instead
of proposing it through Dash0 chat.
- Treating
audit mode findings as blocking by default — they're advisory
unless the caller explicitly passed --strict, and even then unlinked
findings never block.
1---2name: measurable3description: Ensures every delivery ships with the telemetry needed to prove its impact and catch its own regressions: RUM/analytics events for user-facing web changes (delegates to rum-tracking), OpenTelemetry traces/metrics/structured logs for new or changed API endpoints, and explicit error/warning signal paths so failures surface instead of going silent. Modes: guide (default), implement, audit, setup. `setup` runs a first-time interview that records the project's telemetry stack, per-package instrumentation approach for monorepos, and regression-detection expectations as a committed Observability Profile. Triggers on "is this measurable", "add telemetry", "instrument this endpoint", "check observability coverage", "add RUM and API telemetry", "will we know if this regresses", "set up observability profile", "/measurable".4license: MIT5---67# Measurable89Makes "we shipped it" and "we can see it" the same statement. A change is10only done when its impact is measurable and its regressions are visible —11this skill decides what telemetry a diff needs, writes or audits it, and12records a per-repo profile so the answer doesn't have to be re-derived13every time.1415> **This `SKILL.md` is a thin index.** Detailed rules live in `rules/*.md`16> and load on demand. The profile template lives in `templates/*.md`.17>18> **Composes, does not duplicate.** Frontend event design is19> [`rum-tracking`](../../analysis/rum-tracking/SKILL.md)'s job — this skill20> only decides *whether* a user-facing change needs RUM and hands off to it.21> Backend span/metric semantic conventions belong to the `otel-instrumentation`22> and `otel-semantic-conventions` skills (from the23> [dash0 agent-skills repo](https://github.com/dash0hq/agent-skills)) when24> installed — invoked via `Skill()`, skipped silently otherwise, with25> [`rules/backend-instrumentation.md`](./rules/backend-instrumentation.md) as26> the built-in fallback. Persistence for the Observability Profile is27> [`persistent-memory`](../../authoring/persistent-memory/SKILL.md)'s28> `project-shared` tier — this skill never invents its own storage layer.2930---3132## Mode Detection3334Parse `$1` as the mode.35State the detected mode in one line before continuing.3637| Mode | Default | Trigger |38| ----------- | ------- | ------------------------------------------------------------------------- |39| `guide` | **yes** | "is this measurable", "what telemetry do I need", default if no mode |40| `implement` | | "add telemetry", "instrument this", "add RUM and API telemetry" |41| `audit` | | "audit observability", "check observability coverage", "--diff", aw Phase 4 gate |42| `setup` | | "set up observability profile", "first-time setup", "/measurable setup" |4344If `$1` is a diff, PR, file, or directory, treat it as the scope for45`implement` or `audit`.4647---4849## Workflow by Mode5051### Guide mode (default)5253The user is deciding *whether* and *what* telemetry a change needs.54551. Load [`rules/scope-detection.md`](./rules/scope-detection.md) and classify56 the change: frontend (web), frontend (mobile), backend/API, infra, or57 mixed. In a monorepo, check for a committed Observability Profile first58 (see [`rules/setup-profile.md`](./rules/setup-profile.md)) so package59 boundaries and stack choices don't have to be re-guessed.602. For a frontend classification, recommend the user-facing events per61 [`rules/frontend-rum.md`](./rules/frontend-rum.md) (thin pointer into62 `rum-tracking`).633. For a backend/API classification, recommend the spans, metrics, and64 structured logs per65 [`rules/backend-instrumentation.md`](./rules/backend-instrumentation.md).664. Regardless of classification, name the specific regression signal —67 the metric, alert, or dashboard panel that would turn red if this change68 broke — per [`rules/regression-signals.md`](./rules/regression-signals.md).69 "We added a log line" is not a regression signal; "P99 latency on70 `POST /checkout` is now tracked and alerts at 2× baseline" is.715. Do not prescribe code yet — that's `implement` mode. Guide mode ends with72 a short, concrete list: signals to add, and why each one is the one that73 would catch a regression.7475### Implement mode7677The user (or the `autonomous-workflow` Phase 3 trigger) wants the78instrumentation written.79801. Run the Guide-mode classification (Step 1 above) first — never write81 telemetry code without first stating what kind of change this is.822. Frontend user-facing change → delegate:83 ```84 Skill("rum-tracking", "implement", "<target>")85 ```86 This skill does not re-implement event design; it only confirms the87 delegation happened and that the resulting events map to a named88 regression signal (Step 4 above).893. Backend/API change → follow90 [`rules/backend-instrumentation.md`](./rules/backend-instrumentation.md):91 a span per new/changed operation with OTel semantic-convention attributes,92 a RED metric (rate, errors, duration) if the operation is on a hot path,93 and a structured log at the point of failure. Prefer delegating to94 `Skill("otel-instrumentation")` / `Skill("otel-semantic-conventions")`95 when installed; the rule file is the fallback when they are not.964. Either path → apply97 [`rules/regression-signals.md`](./rules/regression-signals.md) so errors98 and warnings are never silent: span status set on failure, a log at99 `error`/`warn` severity with enough context to triage without100 reproducing, and — when the Observability Profile names an existing101 dashboard or check rule for this package — a note that it now covers102 the new path (never auto-edit dashboards/alerts; that's `dash0`'s job103 in Dash0 chat, not this skill's).1045. Report what was added as a short "Observability" summary (one line per105 signal, with file:line) — `autonomous-workflow` Phase 6 folds this into106 the PR walkthrough.107108### Audit mode109110The user (or the `autonomous-workflow` Phase 4 gate) wants an existing diff111checked for coverage gaps, without writing anything.1121131. Walk [`rules/audit-checklist.md`](./rules/audit-checklist.md) against the114 diff (or the target file/directory if no diff is given).1152. Classify each finding: `missing` (no signal at all for a changed path116 that needs one), `unlinked` (a signal exists but maps to no regression117 detector — Step 4 of Guide mode), or `pass`.1183. Cite a file path and line number for every finding.1194. Output a ranked list. **Advisory by default** — `missing` and `unlinked`120 findings are both reported, neither blocks. Pass `--strict` to make121 `missing` findings on `web`/`mobile`/`api`/`worker` paths block the122 caller's gate (`unlinked` stays advisory even in `--strict`, since not123 every signal needs a bespoke dashboard on day one). This mirrors how124 `critical` and `optimize-approach` ship non-blocking by default in this125 registry — a brand-new coverage heuristic earns a hard gate only once a126 team has opted in, not on day one.1275. Never auto-edit in `audit` mode — that is what `implement` mode is for.128129**Callers of `audit` mode.** `autonomous-workflow` Phase 4 (its Observability Gate) and the130`pr-reviewer` agent's measurability lens (Step 2.4e, via131`agents/shared/rules/measurability-review.md`) are both `audit`-only consumers. `autonomous-workflow`132stays advisory unless a run opts into `--observability-strict`; the **reviewer defaults to strict** (a133repo opts down with `measurable: advisory`), because a merged change that ships a new failure mode with134no signal is the case the lens exists for. The reviewer additionally gates the call behind two135conditions of its own — the diff must touch a `web`/`mobile`/`api`/`worker` path **and** add or alter136observable behaviour — so a refactor PR never reaches this mode at all. Neither caller may invoke137`implement`: one is a gate, the other is read-only.138139### Setup mode140141First-time (or repo-onboarding) interview that records durable project142facts so every later `guide`/`implement`/`audit` run stops re-deriving them.1431441. Follow [`rules/setup-profile.md`](./rules/setup-profile.md) end to end:145 interview, monorepo package map, write via `persistent-memory`146 (`project-shared` tier), confirm.1472. Re-run any time the stack changes or a new package is added — `setup` is148 idempotent and updates the existing profile rather than duplicating it.149150---151152## Required Reading by Mode153154Load on demand — do not preload.155156| Mode | Files |157| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |158| `guide` | [`rules/scope-detection.md`](./rules/scope-detection.md), [`rules/frontend-rum.md`](./rules/frontend-rum.md), [`rules/backend-instrumentation.md`](./rules/backend-instrumentation.md), [`rules/regression-signals.md`](./rules/regression-signals.md) |159| `implement` | Same as `guide`, plus the delegated skill's own required reading (`rum-tracking`, `otel-instrumentation` when installed) |160| `audit` | [`rules/audit-checklist.md`](./rules/audit-checklist.md), [`rules/scope-detection.md`](./rules/scope-detection.md) |161| `setup` | [`rules/setup-profile.md`](./rules/setup-profile.md), [`templates/observability-profile.template.md`](./templates/observability-profile.template.md) |162163---164165## Core Principles1661671. **A signal without a regression detector is not coverage.** Emitting a168 span or a log is necessary but not sufficient — name what would alert or169 what dashboard would show the break. Anti-pattern: "instrumented" meaning170 only "some code now calls a tracer."1712. **RUM and API telemetry are two different jobs, not one.** Frontend172 product-analytics event design stays owned by `rum-tracking`; this skill173 decides *whether* a change needs it and folds it into the same coverage174 picture as backend spans/metrics/logs.1753. **The Observability Profile is the source of truth for "how does this176 repo do telemetry."** Never re-guess the stack or the monorepo package177 map when a profile exists; run `setup` once, `guide`/`audit` read it after.1784. **Errors and warnings are first-class deliverables.** A change that adds179 a new failure mode without a way to see that failure mode in production180 is incomplete, regardless of test coverage.1815. **Advisory on frontend/backend code, hands-off on Dash0 config.** This182 skill writes application-level instrumentation. It never creates or edits183 dashboards, alerts, or SLOs directly — those are proposed through Dash0184 chat (the `dash0` agent) so a human reviews and creates them there.1856. **Companions skip silently.** `rum-tracking`, `otel-instrumentation`,186 `otel-semantic-conventions`, and `persistent-memory` are all optional —187 degrade to the built-in rule files and say so in one line, never block.188189## Anti-patterns (one-liners)190191- Calling a change "instrumented" because a log line was added, with no192 metric or alert that would ever surface a regression.193- Re-deriving the monorepo package map or telemetry stack every run instead194 of running `setup` once and reading the profile.195- Writing frontend analytics events inline instead of delegating to196 `rum-tracking`'s centralized wrapper.197- Swallowing an error (`catch {}`) without a log at `error` severity and a198 span status flip.199- Editing a Dash0 dashboard or check rule directly from this skill instead200 of proposing it through Dash0 chat.201- Treating `audit` mode findings as blocking by default — they're advisory202 unless the caller explicitly passed `--strict`, and even then `unlinked`203 findings never block.