/** * Join-discovery for the cross-pillar bridge. * * Finds the best structural join label between the Log10x metric universe * (fetched via the existing prometheus gateway `fetchLabelValues`) and * the customer metric backend (fetched via `CustomerMetricsBackend.listLabelValues`) * using Jaccard similarity on label value sets. * * The join key is a pair `(log10x_side_label, customer_side_label)` whose * values overlap highly enough to be considered the same physical or * logical dimension across both backends. The default minimum_jaccard * floor is 0.7; pairs below the floor are not returned as the primary * join, though runner-ups above 0.5 are surfaced for agent awareness. * * The join discovery result is cached per-session keyed by * `(environment, customer_backend_endpoint)` so the cross-pillar * primitives (metrics_that_moved, rank_by_shape_similarity, * metric_overlay) can auto-run it once and never re-probe during the * same MCP process lifetime. */ import type { EnvConfig } from './environments.js'; import type { CustomerMetricsBackend } from './customer-metrics.js'; /** * Log10x-side labels that are candidates for a structural join as of v1.4. * Deliberately excludes k8s_node (not populated by the current k8s * enrichment module) and high-cardinality identity labels like * `message_pattern`, `tenx_parent_uuid`, `tenx_pipeline_uuid`, etc. */ export declare const LOG10X_JOIN_CANDIDATES: readonly ["tenx_user_service", "k8s_pod", "k8s_namespace", "k8s_container", "http_code", "severity_level"]; export type Log10xJoinCandidate = (typeof LOG10X_JOIN_CANDIDATES)[number]; /** * Common customer-side label names worth probing first. The discovery * pass probes ALL labels from the backend, but preferring these up front * keeps the common case fast. */ export declare const PREFERRED_CUSTOMER_LABELS: readonly ["service", "service_name", "service.name", "dd.service", "kube_service", "app", "pod", "kube_pod", "kubernetes_pod_name", "namespace", "kube_namespace", "container", "kube_container"]; export interface JoinPair { log10xSide: string; customerSide: string; jaccard: number; sharedValues: number; log10xOnlyValues: number; customerOnlyValues: number; /** True when both labels denote the same canonical dimension by name * (DIMENSION_ALIASES). A join accepted on this basis below the strict * value floor is a "name-aware" join — surfaced so downstream tiering / * rendering can note it joined on name + partial value, not strong value * overlap. */ nameAliased?: boolean; } export interface JoinDiscoveryResult { status: 'joined' | 'no_join_available'; /** Best pair above the minimum_jaccard floor. Undefined when status = no_join_available. */ joinKey?: JoinPair; /** Other pairs above 0.5 but below the primary pair. */ runnerUps: JoinPair[]; /** Every pair probed, including sub-floor ones. Used for refusal diagnostics. */ probed: JoinPair[]; /** Labels we considered on each side. */ probedLabelsLog10x: string[]; probedLabelsCustomer: string[]; /** Whether this result came from the session cache. */ cachedForSession: boolean; } export interface DiscoverJoinOptions { minimumJaccard?: number; /** Maximum label values to fetch per side per label. High-cardinality labels skipped. */ maxValuesPerLabel?: number; /** Restrict to a specific subset of customer-side labels. */ candidateLabels?: string[]; /** * Window (seconds) for label value enumeration. When set, both the Log10x * and customer backends are queried with `start = now - windowSeconds` and * `end = now`, filtering out stale label values from series that stopped * emitting samples. Critical for environments where historical replay data * or decommissioned services leave orphan label values in the metric store * — those drag Jaccard down and cause false `no_join_available` refusals. * * Recommended default: 600 seconds (10 minutes). Longer windows pick up * bursty services; shorter windows tighten the current state. */ windowSeconds?: number; } /** * Run join discovery against the customer backend. * * Does NOT consult the session cache — callers who want cached behavior * should use `getOrDiscoverJoin()` below. */ export declare function discoverJoin(env: EnvConfig, backend: CustomerMetricsBackend, options?: DiscoverJoinOptions): Promise; /** * Get a cached join discovery result, or run discoverJoin and cache it. * This is the function the higher-level tools should call by default. */ export declare function getOrDiscoverJoin(env: EnvConfig, backend: CustomerMetricsBackend, options?: DiscoverJoinOptions): Promise; /** Clear the session cache. Exposed for tests. */ export declare function clearJoinCacheForTest(): void;