CtrlK
BlogDocsLog inGet started
Tessl Logo

measurable

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, and structured logs for new or changed API endpoints, and explicit error/warning signal paths so failures surface instead of going silent. Knows OpenTelemetry Weaver — validating a signal against a semantic-convention registry, and treating a renamed metric or attribute as the breaking change it is. Modes: guide (default), implement, audit, setup. `setup` interviews the project once, recording its telemetry stack, schema (Weaver registry), 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", "will we know if this regresses", "does this break the telemetry contract", "/measurable".

68

Quality

86%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

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(), otherwise skipped with a one-line report, 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. OpenTelemetry Weaver is an external CLI rather than a skill, so rules/weaver-schema.md owns it end to end and is advisory in every mode — a repo that has not adopted Weaver loses one line of output, never a finding.


Mode Detection

Parse $1 as the mode. State the detected mode in one line before continuing.

ModeDefaultTrigger
guideyes"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.

  1. 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.
  2. For a frontend classification, recommend the user-facing events per rules/frontend-rum.md (thin pointer into rum-tracking).
  3. For a backend/API classification, recommend the spans, metrics, and structured logs per rules/backend-instrumentation.md.
  4. 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.
  5. If the change introduces or renames a signal name, run Step 1 of rules/weaver-schema.md. A rename is a breaking change whose symptom is a query that quietly returns nothing, so it is the one regression the previous step cannot see.
  6. 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.

  1. Run the Guide-mode classification (Step 1 above) first — never write telemetry code without first stating what kind of change this is.
  2. 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).
  3. 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. When the Observability Profile names a Weaver registry, add the new signal to it in the same diff and re-run weaver registry check — rules/weaver-schema.md. Instrumentation emitting a name the registry does not define is the schema drift the registry exists to prevent, and it lands silently.
  4. 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).
  5. 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.
  6. Prove it. Step 5's summary is a static file:line claim; this step turns it into an executed one:
    Skill("observe-run")
      command:      <the command that exercises the new/changed operation>
      expectations: "the run emits one span per invocation of <operation>, each a child of <parent span>"
                    "the new attribute's distinct-value set stays bounded across the run"
    These are kinds 1 + 2 (span count, then parent/child structure) and kind 6 (attribute cardinality) from observe-run's closed list of seven allowed kinds — both behavioral, both graded against an actual run, never against the diff read back. Note the phrasing of the first one: "a span named X exists" is answerable by reading the source that was just written, so it is refused by the provenance rule as by-construction. The expectation has to name something only the run can settle — here the count per invocation and the parent it actually attached to, which a startSpan call site alone does not determine. Phrase every expectation as one of those seven: the list is closed, and an expectation outside it is refused rather than graded. Cardinality is also the check measurable most needs here, since a new unbounded attribute is exactly what makes a signal unsafe as a metric dimension. Advisory, and skipped with one report line when observe-run (or its Observability Profile dev target) is unavailable, consistent with Core Principle 6 above — this step never blocks implement mode on the companion's absence.

Audit mode

The user (or the autonomous-workflow Phase 4 gate) wants an existing diff checked for coverage gaps, without writing anything.

  1. Walk rules/audit-checklist.md against the diff (or the target file/directory if no diff is given).
  2. 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.
  3. Cite a file path and line number for every finding.
  4. 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.
  5. Never auto-edit in audit mode — that is what implement mode is for.
  6. When the Observability Profile names a Weaver registry, walk the registry-conformance row of rules/audit-checklist.md too, and fold its output into the same three verdicts. Weaver never adds a fourth verdict — the pr-reviewer lens maps exactly three, so a fourth reaches no surface.

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.

  1. Follow rules/setup-profile.md end to end: interview, monorepo package map, write via persistent-memory (project-shared tier), confirm.
  2. 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.

ModeFiles
guiderules/scope-detection.md, rules/frontend-rum.md, rules/backend-instrumentation.md, rules/regression-signals.md, and rules/weaver-schema.md when the change adds or renames a signal name
implementSame as guide, plus the delegated skill's own required reading (rum-tracking, otel-instrumentation when installed)
auditrules/audit-checklist.md, rules/scope-detection.md, and rules/weaver-schema.md when the Observability Profile names a registry
setuprules/setup-profile.md, templates/observability-profile.template.md

Core Principles

  1. 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."
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. Companions never block, and never skip silently. rum-tracking, otel-instrumentation, otel-semantic-conventions, persistent-memory, and the weaver CLI are all optional — degrade to the built-in rule files and say so in one line (<name> — skipped (<reason>)), never block.
  7. The signal's name is part of its contract. A renamed metric or attribute breaks every dashboard and check rule reading the old name, and it breaks them quietly — no error, no failing test, just a panel that stopped having data. Principle 1 asks whether something watches the signal; this one asks whether it is still watching the same signal, and rules/weaver-schema.md is how it is answered mechanically rather than by memory.

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.
  • Shipping a renamed metric or attribute as a non-breaking change because no test failed — no test can fail, the consumers are dashboards and check rules.
  • Citing a green weaver registry check as evidence a change is instrumented — it validates the schema, and a registry full of signals no code emits passes it.
  • Bundling the adoption of a Weaver registry into an unrelated feature diff instead of proposing it as its own change.
Repository
mthines/agent-skills
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.