polyc-query 2026.9.6

The Query plane's read model: a DataFusion engine over signed projection artifacts, behind a verified credential.
//! Prometheus metrics for the projected query path's own observability.
//!
//! Registered into the process default registry — same pattern as this
//! workspace's other component-level `metrics.rs` modules
//! (`polyc-eventlog`'s is the reference): no separate scrape endpoint, no
//! separate registry plumbing. The `polyc-runtime` side-server's `/metrics`
//! handler gathers the default registry, so these series show up there for
//! free in any binary that links this crate and calls [`crate::init_metrics`]
//! at startup — `crates/query-service`'s `serve` does exactly that.

use std::sync::OnceLock;

use prometheus::{IntCounterVec, register_int_counter_vec};

/// Every (`realm`, `principal_kind`) label pair
/// [`record_catalog_described`] can produce. The catalog admits exactly the
/// self-service caller set — the same allowlist the edge listener applies —
/// so only those four kinds can ever reach the call. Pre-created so the
/// series scrape as zero before the first lookup; a refused call records
/// nothing.
const CATALOG_LABELS: [(&str, &str); 8] = [
    ("visible", "persona"),
    ("visible", "conversation_grant_web_session"),
    ("visible", "conversation_grant_persona"),
    ("visible", "admin_fleet"),
    ("fleet", "persona"),
    ("fleet", "conversation_grant_web_session"),
    ("fleet", "conversation_grant_persona"),
    ("fleet", "admin_fleet"),
];

/// Count of `DescribeCatalog` calls answered — the pure catalog lookup is
/// deliberately unaudited (POLY-367), so this counter is its only usage
/// signal, labeled `realm` and `principal_kind`.
fn catalog_described_total() -> &'static IntCounterVec {
    static V: OnceLock<IntCounterVec> = OnceLock::new();
    V.get_or_init(|| {
        register_int_counter_vec!(
            "polychrome_query_catalog_described_total",
            "Count of DescribeCatalog lookups answered, by realm and principal kind.",
            &["realm", "principal_kind"]
        )
        .expect("register polychrome_query_catalog_described_total")
    })
}

/// Record one answered `DescribeCatalog` call, labeled `realm` and
/// `principal_kind`.
pub(crate) fn record_catalog_described(realm: &str, principal_kind: &str) {
    catalog_described_total()
        .with_label_values(&[realm, principal_kind])
        .inc();
}

/// Every `reason` label value [`record_statement_refusal`] can produce —
/// one per [`crate::statement_gate::StatementRejected`] reason key. Kept
/// in a constant so [`force`] can pre-create each series and an added
/// variant fails the completeness test, not just a scrape.
pub(crate) const REFUSAL_REASONS: [&str; 11] = [
    "statement_kind",
    "statement_parse",
    "function_surface",
    "expression_nodes",
    "expression_depth",
    "function_calls",
    "select_items",
    "query_nodes",
    "expression_output_references",
    "column_fanout",
    "statement_column_references",
];

/// Count of statements the AST gate refused, labeled `realm`,
/// `principal_kind`, and the bounded `reason` key
/// [`crate::statement_gate::StatementRejected::reason_key`] reports
/// (POLY-371). The label set is closed: no SQL text and no caller-chosen
/// name can ever reach a series.
fn statement_refusals_total() -> &'static IntCounterVec {
    static V: OnceLock<IntCounterVec> = OnceLock::new();
    V.get_or_init(|| {
        register_int_counter_vec!(
            "polychrome_query_statement_refusals_total",
            "Count of statements the query gate refused, by realm, principal kind, and reason.",
            &["realm", "principal_kind", "reason"]
        )
        .expect("register polychrome_query_statement_refusals_total")
    })
}

/// Record one refused statement, labeled `realm`, `principal_kind`, and
/// the gate's bounded `reason` key.
pub(crate) fn record_statement_refusal(realm: &str, principal_kind: &str, reason: &str) {
    statement_refusals_total()
        .with_label_values(&[realm, principal_kind, reason])
        .inc();
}

/// Force-register this module's series with every known label pair
/// pre-created (zero-valued), so `/metrics` answers for them from the first
/// scrape — not only after the first call happens to touch one. See
/// [`crate::init_metrics`].
///
/// An `IntCounterVec` produces NO scrape output for a label combination that
/// has never been touched — registering the vec alone is not enough.
/// `with_label_values` creates the zero-valued child without recording an
/// observation, which is what makes it appear.
pub(crate) fn force() {
    for pair in CATALOG_LABELS {
        catalog_described_total().with_label_values(&<[&str; 2]>::from(pair));
        for reason in REFUSAL_REASONS {
            statement_refusals_total().with_label_values(&[pair.0, pair.1, reason]);
        }
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::pedantic, clippy::nursery, missing_docs)]

    use prometheus::{Encoder as _, TextEncoder};

    use super::record_catalog_described;

    fn scrape() -> String {
        let mut buf = Vec::new();
        TextEncoder::new()
            .encode(&prometheus::default_registry().gather(), &mut buf)
            .expect("encode");
        String::from_utf8(buf).expect("utf8")
    }

    /// `polychrome_query_catalog_described_total` increments by exactly one
    /// per answered call, labeled `realm` and `principal_kind` — the unaudited
    /// lookup's only usage signal (POLY-367).
    #[test]
    fn record_catalog_described_increments_by_exactly_one() {
        let metric = "polychrome_query_catalog_described_total";
        let needle = |text: &str, realm: &str, kind: &str| {
            let pattern = format!("{metric}{{principal_kind=\"{kind}\",realm=\"{realm}\"}} ");
            text.lines()
                .find(|line| line.starts_with(&pattern))
                .and_then(|line| line.rsplit(' ').next())
                .and_then(|v| v.parse::<f64>().ok())
                .unwrap_or(0.0)
        };
        let before = needle(&scrape(), "visible", "persona");
        record_catalog_described("visible", "persona");
        let after = needle(&scrape(), "visible", "persona");
        assert_eq!(after - before, 1.0, "{metric} must increment by exactly 1");
        assert_eq!(
            needle(&scrape(), "fleet", "admin_fleet"),
            0.0,
            "an unrelated label pair is untouched"
        );
    }
}