Skip to content

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.