Metrics that moved
Step 1 of the three-step cross-pillar correlation flow. Partitions an anchor's time window into "high phase" (anchor > anchor median) and "low phase", then for each candidate metric computes the relative gap between phase means. Candidates whose gap meets the floor (default 15%) are "moved" — they co-varied with the anchor.
Returns a deterministic ranked list of (metric, gap_pct, direction). No Pearson, no tier labels, no causal framing.
Use this tool first to narrow the candidate pool before calling rank_by_shape_similarity.
Example
You
which metrics moved when Payment_Gateway_Timeout spiked?
Log10x
4 metrics moved with the anchor (phase gap ≥ 15%).
| Metric | Gap | Direction |
|---|---|---|
apm_request_duration_p99{service="payments"} |
68% | up with anchor |
http_client_requests_total{status="503"} |
52% | up with anchor |
db_connection_pool_active |
31% | up with anchor |
apm_request_duration_p50{service="payments"} |
18% | up with anchor |
More to ask
- "which metrics moved when this pattern spiked, 2h window"
- "rank these candidates by shape similarity" → routes to log10x_rank_by_shape_similarity
Prerequisites
LOG10X_CUSTOMER_METRICS_URL configured. Reporter deployed for log10x pattern anchors.
Schema and samples
Input schema
Agent-facing JSON Schema (the canonical shape the MCP server publishes via tools/list):
{
"type": "object",
"properties": {
"anchor_type": {
"type": "string",
"enum": [
"log10x_pattern",
"customer_metric"
],
"description": "Anchor side. `log10x_pattern` = anchor is a 10x pattern. `customer_metric` = anchor is a customer PromQL."
},
"anchor": {
"type": "string",
"description": "Anchor identity (pattern symbol_message OR customer PromQL expression)."
},
"candidates": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 100,
"description": "Customer-side PromQL expressions to evaluate (max 100). An AI caller reasoning over results can't meaningfully digest more than a few dozen; the cap reflects that, not a backend constraint. Pre-filter with `metrics_sharing_resource` or label-scoped `customer_metrics_query` queries."
},
"window": {
"type": "string",
"default": "1h",
"description": "Time window. Alias: `timeRange`."
},
"timeRange": {
"type": "string"
},
"step": {
"type": "string",
"default": "30s",
"description": "Bucket step."
},
"phase_gap_floor": {
"type": "number",
"minimum": 0,
"maximum": 1,
"default": 0.15,
"description": "Relative gap floor between anchor-high and anchor-low phase means. Candidate is \"moved\" iff its gap ≥ this. Default 0.15 (=15%) is an uncalibrated default — output is tagged `unvalidated_default` until a caller-side calibration overrides it. See `docs/cross-pillar-primitives.md` for the calibration playbook."
},
"environment": {
"type": "string"
}
},
"required": [
"anchor_type",
"anchor",
"candidates"
],
"additionalProperties": false
}
Source: src/tools/metrics-that-moved.ts.
Output schema
The data block inside the StructuredOutput envelope:
interface ToolData {
moved: Array<{
candidate: string;
gap_pct: number;
direction: 'up_with_anchor' | 'down_with_anchor';
mean_high_phase: number;
mean_low_phase: number;
}>;
not_moved: string[];
anchor_dispersion: number;
phase_gap_floor_used: number;
calibration_tag?: 'unvalidated_default';
}
Envelope-level fields: summary.headline, actions[] (routes to log10x_rank_by_shape_similarity), schema_epoch.