Oodle Triage — Right-Side Observability
Turn an alert into evidence, not narrative. This skill gathers production context
and files disciplined tickets. It closes the loop opened on the left: it reads the
O11y Change Context manifest on recent PRs to
connect a firing alert to the change that likely caused it.
Prime directive: separate what is proven from what is inferred at every
step. A confirmed symptom, a leading hypothesis, and the exact missing evidence
beats a tidy root-cause story built on correlation. Evidence before assertions.
Modes
- Mode A — Triage context: input is a single alert, a tracker ticket id, or a
symptom description → produce a context report and optionally update the ticket.
- Mode B — Auto oncall triage: input is a time window (and a tracker parent
issue) → enumerate everything that fired, dedupe, and file/update sub-issues.
Designed to run on a cadence.
If the input names one alert/ticket/symptom, use Mode A. If it asks to triage a
window or "everything that fired," use Mode B (which reuses Mode A per alert).
Discovery (do this first)
Resolve backends by
capability and tool shape, never by a hard-coded server
name (names vary:
,
,
,
, or customer-custom).
- Observability MCP — find tools for alerts/monitors, metric (PromQL) queries,
logs, and traces. If the suite matches Oodle's shape, use the tight path: select
the environment that owns the service, and load a matching
workflow when one fits the problem (e.g. Kubernetes debugging, alert-noise
analysis) before low-level calls.
- Issue-tracker MCP — find the tracker in use. Linear is the worked example
below; Jira is the analog (issue → sub-issue, states, comments map across).
- If a backend is missing, do what the available signal allows and state the gap.
Mode A — Triage context
- Establish ground truth, in writing. If given a ticket, fetch it for scope.
Pin service/component, cluster/env, pod(s), container, and the precise time
window before querying anything. Convert the window to both UTC and the
reporter's local zone — mixing them silently is a classic error.
- Confirm the symptom with hard signals before theorizing: restart/OOM
reason, error rate, latency, resource usage vs limit, event logs. State the
confirmed symptom in one line; everything after is explanation.
- Learn the instrumentation from the code. Read the relevant service code for
the actual metric names, log strings, and span attributes — do not guess
them. Note explicitly what is and isn't captured; knowing what is missing
reveals which questions the telemetry cannot answer.
- Triangulate across telemetry — don't lean on one source. Metrics (grouped
by every dimension that localizes blame: service, tenant, operation, pod,
status), logs from caller and callee on the path (read ERROR/WARN and
access logs, widen the filter if a reported log isn't found), traces end to
end, and profiles for resource incidents.
- Correlate with recent changes (loop closes here). Find recent PRs touching
the alerting service (via the GitHub or Linear MCP, or the CLI when no
GitHub MCP is present) and read their
O11y Change Context blocks. items
and focus the hypotheses (a becomes the leading
hypothesis); confirms the alert↔code link; explains
evidence the telemetry was never built to provide.
- Track and label every finding
Confirmed | Inferred | Unknown
. A
configured ceiling or default is not a measurement; co-occurrence is not
causation. Actively try to falsify the leading hypothesis with one
measurement — eliminating a candidate is worth more than adding support.
- When confirmation is impossible, stop and produce a ranked missing-evidence list:
for each item, which hypothesis it would confirm/refute, where it likely lives,
and whether it is accessible. Then ask to unblock the top item rather than
guessing past it.
Output — a short, honest report: confirmed Symptom (with UTC+local
timestamps), Attribution (who/what/where, to the extent proven), Leading
hypothesis (proven vs inferred, plainly), Ruled out (with the measurement),
Missing evidence (the ranked list). Offer to post it as a comment on the
tracker ticket.
Mode B — Auto oncall triage
Run Mode A's investigation per alert, wrapped in enumerate → suppress → dedupe →
file. Match-check strictly precedes any create so reruns never double-file.
- Enumerate what fired in the window — the alert instances that reached the
firing state. Never treat a pending/for-not-yet-satisfied condition as a
fire: it sends no notification and must not be triaged or filed. Confirm a
real fire from the alert-state signal or trigger history.
- Enrich each: still-active now, noise category (flapping/storm/perpetual/
auto-resolving/boundary) and trigger count over ~7d, muted? (an active
muting rule whose matchers all match this alert's monitor + scope), and
routed? (does the monitor page anyone, or is it unrouted).
- Suppress muted and unrouted alerts — they are not actionable oncall signal.
Do not file them. If a stale ticket exists for a now-muted or now-unrouted
alert, close it with a comment stating the reason (muting rule id + matchers,
or unrouted monitor id). Suppress the specific instance, not a whole alert
class — routing is per-monitor per-env.
- Collapse storms — many series of one monitor firing together become one
logical alert → one ticket, not N.
- Investigate each distinct fired alert with Mode A, depth scaled to
severity. Manifest correlation feeds probable-cause and suggested-fix.
- Dedupe & file against the tracker by semantic match anchored on the
fingerprint (env + monitor + scope): no match → create; match open → comment
the new occurrence; match closed → reopen and comment. Set priority from
severity. Retry a failed write once; never leave a half-created duplicate.
Rerunning the same window is idempotent.
Fingerprint block
Every filed ticket carries a stable fingerprint so future runs match it. Keep the
format constant:
## Fingerprint
- env: <env>
- monitor: <monitor id/name>
- scope: <key=value scope labels>
- links: <deep links to the backend>
Genericity vs Oodle-tight
The
discipline is vendor-neutral: confirmed-vs-inferred labeling, firing-only
enumeration, suppressing muted/unrouted noise, storm collapse, fingerprint dedup,
and manifest correlation apply to any backend. The
mechanics are backend-
specific: Oodle exposes an
-style state metric,
with typed
matchers, and a monitor routing flag; a different vendor's MCP supplies its own
equivalents. Use the equivalent where it exists; skip a step where the concept is
genuinely absent — never invent a mechanic a backend does not have.
For the Oodle CLI path when deeper queries help, lean on
oodle-metrics,
oodle-logs, and
oodle-traces rather than restating them here.