Policy Observability
Policy decisions emit Prometheus metrics and telemetry events so operators can monitor enforcement health, detect misconfigured rules, and tune thresholds.
Metrics
Python SDK metrics
Exposed on a dedicated CollectorRegistry in the SDK process:
| Metric | Type | Labels | Description |
|---|---|---|---|
pavri_policy_evaluations_total | Counter | result, policy_type | Every policy evaluation |
pavri_policy_evaluation_duration_seconds | Histogram | — | Evaluation latency |
pavri_policy_cache_status | Counter | status (hit/miss/stale) | Cache health |
pavri_policy_sync_lag_seconds | Gauge | — | Time since last successful sync |
pavri_policy_denials_total | Counter | rule_type | Denied actions by rule category |
All labels are low-cardinality per the observability plan. No org_id, agent_id, or session_id in metric labels — those belong in telemetry events and logs.
Go policy-svc metrics
Exposed on /metrics (Prometheus scrape endpoint):
| Metric | Type | Labels | Description |
|---|---|---|---|
pavri_policy_bootstrap_requests_total | Counter | status (ok/error) | Bootstrap request outcomes |
pavri_policy_watch_streams_active | Gauge | — | Currently connected watch streams |
pavri_policy_snapshot_latency_seconds | Histogram | — | Snapshot generation time |
pavri_policy_crud_operations_total | Counter | operation, status | CRUD operation counts |
pavri_policy_postgres_query_latency_seconds | Histogram | operation | Database query latency |
Telemetry events
Every non-allow policy decision emits a policy_eval event to the telemetry pipeline:
{
"event_type": "policy_eval",
"agent_id": "agt-01H...",
"session_id": "ses-01H...",
"payload": {
"action": "tool:http.gateway.submit",
"decision": "deny",
"reason": "tool http.gateway.submit not in allowlist",
"policy_id": "pol-abc123",
"rule_id": "r1"
}
}
These events flow through the standard pipeline: SDK → gateway → ingest → JetStream → ClickHouse. They are queryable alongside tool call and model invocation events for forensic review.
What to monitor
Healthy policy system
pavri_policy_cache_status{status="hit"}is consistently highpavri_policy_sync_lag_secondsstays near zeropavri_policy_evaluations_totalgrows steadilypavri_policy_denials_totalis low relative to total evaluations
Warning signs
- Cache misses spiking — agents are evaluating without a policy snapshot. Check backend connectivity and sync health.
- Sync lag increasing — the watch stream may be disconnected. Check
pavri_policy_watch_streams_activeand policy-svc logs. - Denial rate spiking — either a new restrictive policy was deployed, or agent behavior has changed. Cross-reference with recent policy changes in the audit trail.
- Evaluation latency increasing — too many rules or complex regex patterns. Consider simplifying data classification patterns.
Dashboard visibility
The policy library in the dashboard shows:
- Enabled count — policies actively enforcing
- Shadow count — policies in rollout validation
- Validation warnings — policies with configuration issues
- Critical blocks — policies with blocking effects
Each policy's detail view shows its enforcement mode, scope, rule blocks, and impact metrics.
Deferred
- Grafana dashboard templates for policy metrics (tracked for ops hardening)
- Policy decision drill-down in the dashboard (click a metric → see matching events)
- Rollout promotion observability (observe → enforce stage tracking) — Phase 2