Skip to content

Pattern diff

Compare pattern presence in two adjacent windows when the question is "what changed across this boundary?". Returns four ranked sets (new, retired, persistent, re_emerged) plus co-emergence clusters of patterns whose first_seen timestamps cluster within a tight window. Pattern identity is stable across log-format drift, so the set diff stays coherent across time boundaries.

Example

You

what changed since yesterday in payment?

Log10x

Pattern diff over yesterday vs today in payment: 7 new, 3 retired, 41 persistent, 2 re-emerged. 1 co-emergence cluster: 5 patterns first seen within 14s around 09:42 UTC. Worth checking the deploy log around that timestamp.

More to ask

  • "diff patterns this week vs last week"
  • "what new error patterns showed up today in checkout-svc"
  • "any re-emerged patterns over the last 7d"

Prerequisites

Reporter deployed with at least one full timeRange of metrics on each side of the boundary. Re-emergence and co-emergence enrichments need first_seen state, which the Reporter accumulates from first install.

Schema and samples

Input example

Representative call (synthetic, not captured from the live demo env).

{
  "timeRange": "1d",
  "service": "payment",
  "limit": 20,
  "view": "summary"
}
Input schema

Agent-facing JSON Schema (the canonical shape the MCP server publishes via tools/list):

{
  "type": "object",
  "properties": {
    "timeRange": {
      "type": "string",
      "enum": [
        "1h",
        "6h",
        "1d",
        "7d",
        "30d"
      ],
      "default": "1d",
      "description": "Window size on both sides of the boundary. The tool compares the most recent `timeRange` (\"after\") against the immediately preceding `timeRange` (\"before\"). Example: `timeRange: \"1d\"` compares today vs yesterday."
    },
    "service": {
      "type": "string",
      "description": "Service name to scope. Omit for all services."
    },
    "severity": {
      "type": "string",
      "description": "Severity to scope (e.g. `ERROR`, `CRITICAL`)."
    },
    "limit": {
      "type": "number",
      "minimum": 1,
      "maximum": 50,
      "default": 20,
      "description": "Max rows per category (new / retired / persistent / re_emerged). Default 20."
    },
    "co_emergence_window_seconds": {
      "type": "number",
      "minimum": 10,
      "maximum": 600,
      "default": 60,
      "description": "Time spread for clustering co-emergent patterns. Default 60s — tight enough to fingerprint a single deploy."
    },
    "min_co_emergence_cluster_size": {
      "type": "number",
      "minimum": 2,
      "maximum": 20,
      "default": 3,
      "description": "Minimum cluster size to emit. Default 3 — 2 patterns sharing a timestamp is often coincidence."
    },
    "analyzerCost": {
      "type": "number",
      "description": "SIEM ingestion cost in $/GB. Auto-detected from profile."
    },
    "environment": {
      "type": "string",
      "description": "Environment nickname (for multi-env setups)."
    },
    "view": {
      "type": "string",
      "enum": [
        "summary",
        "markdown"
      ],
      "default": "summary",
      "description": "Output format."
    }
  },
  "additionalProperties": false
}

Source: src/tools/pattern-diff.ts.

Output example

Representative envelope (synthetic, not captured from the live demo env). view: "summary" returns the full StructuredOutput with typed data.

Headline (the 1-line agent-facing answer):

Pattern diff over yesterday vs today: 7 new, 3 retired, 2 re-emerged, 41 persistent.

{
  "schema_version": "1.0",
  "schema_epoch": "2026-05-25",
  "tool": "log10x_pattern_diff",
  "generated_at": "2026-06-05T12:00:00.000Z",
  "view": "summary",
  "summary": {
    "headline": "Pattern diff over yesterday vs today: 7 new, 3 retired, 2 re-emerged, 41 persistent.",
    "callout": "1 co-emergence cluster detected (3+ patterns sharing first_seen within 60s) — consider checking your deploy log around the cluster timestamps."
  },
  "data": {
    "time_range": "yesterday vs today",
    "after_window_label": "last 1d",
    "before_window_label": "prior 1d",
    "new": [
      {
        "pattern_hash": "k4Lp9wQrTuV",
        "symbol_message": "PaymentProcessor checkout timeout after retries",
        "severities": ["ERROR"],
        "bytes_now": 142500000,
        "bytes_before": 0,
        "cost_now_usd": 0.21,
        "cost_before_usd": 0,
        "first_seen_age_seconds": 18420,
        "services": [
          {
            "name": "payment",
            "severity": "ERROR",
            "bytes_now": 142500000,
            "bytes_before": 0,
            "cost_now_usd": 0.21,
            "cost_before_usd": 0
          }
        ]
      },
      "... 6 more elided"
    ],
    "retired": [
      {
        "pattern_hash": "rT8mNxYzAbC",
        "symbol_message": "PaymentProcessor legacy SOAP path hit",
        "severities": ["WARN"],
        "bytes_now": 0,
        "bytes_before": 88200000,
        "cost_now_usd": 0,
        "cost_before_usd": 0.13,
        "first_seen_age_seconds": 2592000,
        "services": [
          {
            "name": "payment",
            "severity": "WARN",
            "bytes_now": 0,
            "bytes_before": 88200000,
            "cost_now_usd": 0,
            "cost_before_usd": 0.13
          }
        ]
      },
      "... 2 more elided"
    ],
    "persistent": [
      "... 20 rows elided"
    ],
    "re_emerged": [
      {
        "pattern_hash": "zX2qPpLmKjH",
        "symbol_message": "InventoryCheck stale cache fallback",
        "severities": ["WARN"],
        "bytes_now": 51200000,
        "bytes_before": 0,
        "cost_now_usd": 0.07,
        "cost_before_usd": 0,
        "first_seen_age_seconds": 5184000,
        "services": [
          {
            "name": "payment",
            "severity": "WARN",
            "bytes_now": 51200000,
            "bytes_before": 0,
            "cost_now_usd": 0.07,
            "cost_before_usd": 0
          }
        ]
      },
      "... 1 more elided"
    ],
    "co_emergence_clusters": [
      {
        "patterns": ["k4Lp9wQrTuV", "n7Xm3qPzVbR", "j9KlMnOpQsT", "h2GfHaSdFgY", "p1WeRtYuIoP"],
        "first_seen_window_ts": [1748090520, 1748090534],
        "cluster_size": 5
      }
    ],
    "totals": {
      "new": 7,
      "retired": 3,
      "persistent": 41,
      "re_emerged": 2
    }
  },
  "actions": [
    {
      "tool": "log10x_pattern_examples",
      "args": {
        "pattern": "k4Lp9wQrTuV",
        "timeRange": "1d"
      },
      "reason": "see what the top new pattern actually looks like"
    },
    {
      "tool": "log10x_pattern_trend",
      "args": {
        "pattern": "zX2qPpLmKjH",
        "timeRange": "30d"
      },
      "reason": "inspect the re-emerged pattern's full trajectory — when did it go silent, when did it come back"
    },
    {
      "tool": "log10x_pattern_examples",
      "args": {
        "pattern": "k4Lp9wQrTuV",
        "timeRange": "1d"
      },
      "reason": "inspect the first pattern in the largest co-emergence cluster (5 patterns at 2026-06-04T09:42:00.000Z)"
    }
  ],
  "truncated": false,
  "warnings": []
}
Output schema

The data block inside the StructuredOutput envelope:

interface ToolData {
  time_range: string;
  after_window_label: string;
  before_window_label: string;
  new: Array<{
    pattern_hash: string;
    symbol_message: string;
    severities: string[];
    bytes_now: number;
    bytes_before: number;
    cost_now_usd: number;
    cost_before_usd: number;
    first_seen_age_seconds: number | null;
    services: Array<{
      name: string;
      severity: string;
      bytes_now: number;
      bytes_before: number;
      cost_now_usd: number;
      cost_before_usd: number;
    }>;
  }>;
  retired: Array<{ /* same shape as new[] */ }>;
  persistent: Array<{ /* same shape as new[] */ }>;
  re_emerged: Array<{ /* same shape as new[] */ }>;
  co_emergence_clusters: Array<{
    patterns: string[];
    first_seen_window_ts: [number, number];
    cluster_size: number;
  }>;
  totals: {
    new: number;
    retired: number;
    persistent: number;
    re_emerged: number;
  };
}

Envelope-level fields the agent should also read: summary.headline (1-line answer), summary.callout (co-emergence or re-emergence narrative when present), actions[] (next-call chain hints as {tool, args, reason}), truncated: boolean, schema_epoch (engine-ID stability boundary).