Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt

Use this file to discover all available pages before exploring further.

Governance signals schema

This page documents the platform schema for governance signals, the operator-actionable observation surface introduced in ADR-048.

Tables

governance_signals

The single row per open observation. The platform writes via the governance_signal_emit RPC; consumers (REST handlers, dispatcher, UI, CLI) read directly.
ColumnTypeNotes
idtext PKgs-{12-hex} (mirrors pa- convention from pending_advisories).
scopetext CHECK`platformorgteamagent`.
scope_idtextplatform_id / org_id / team_id (uuid::text) / agent_id.
sourcetext CHECK`sideband.driftsideband.coherencesideband.fault_linesideband.fleet. Future protection./posture.` via ADR-048 amendment.
pattern_typetextFree-form per source (e.g., cluster_partition, pairwise_governance_floor).
severitytext CHECK`infowarnhighcritical`.
detected_attimestamptzDefault now(); refreshed on coalescing upsert.
detected_bytextDetector name (e.g., observer.sweepFleet).
org_idtext FK → orgs.org_idDenormalized for RLS perf.
team_iduuidNullable for platform/org/agent scope.
agent_idstext[]Affected agents — informational fan-out.
detailjsonbPattern-specific payload.
source_refjsonbDetector run / sweep_id / cadence info.
statustext CHECK`openacknowledgedresolveddismissedexpired`.
acknowledged_byuuid FK → auth.users.id
acknowledged_attimestamptz
acknowledged_actor_roletext CHECK`platform_adminorg_ownerorg_adminteam_adminmembersystem` (mirrors ADR-046 actor_role).
resolution_statustext CHECK`action_takenwont_fixduplicatefalse_positiveself_resolved`.
action_takentextOperator-authored note.
resolved_byuuid, resolved_at timestamptz
expires_attimestamptzTTL from posture (default 30d).
webhook_delivery_iduuidLast dispatch attempt FK (informational).
notification_statejsonb{<channel>: {state, attempts, destination_id, delivered_at, last_error}}.
created_at, updated_attimestamptzupdated_at maintained by trigger.

Indexes

-- Write-time idempotency: repeated cron emissions of the same open
-- signal coalesce. The architectural fix to the duplicate-paragraph
-- symptom that motivated ADR-048.
CREATE UNIQUE INDEX governance_signals_open_dedup
  ON governance_signals (scope, scope_id, source, pattern_type)
  WHERE status = 'open';

CREATE INDEX governance_signals_org_status_idx
  ON governance_signals (org_id, status, detected_at DESC);
CREATE INDEX governance_signals_team_status_idx
  ON governance_signals (team_id, status, detected_at DESC)
  WHERE team_id IS NOT NULL;
CREATE INDEX governance_signals_severity_open_idx
  ON governance_signals (severity, detected_at DESC)
  WHERE status = 'open';
CREATE INDEX governance_signals_agent_ids_gin
  ON governance_signals USING GIN (agent_ids);

governance_notification_destinations

ColumnTypeNotes
iduuid PK
org_idtext FK
channeltext CHECK`webhookslackemailpagerduty`.
configjsonbChannel-specific.
filterjsonb{sources?, severities?, scopes?, pattern_types?} AND-folded narrowing.
enabledbooleanDisable without delete to preserve audit.
display_nametextUI label.
last_tested_attimestamptzSet by … /test endpoint.
last_test_status, last_test_errortext

governance_escalation_rules

ColumnTypeNotes
iduuid PK
org_idtext FK
nametextOperator-authored.
predicatejsonb{source?, pattern_type?, severity_min?, severity_max?, scope?, team_id?, threshold_count?, window_minutes?} AND-folded.
destination_idsuuid[]Non-empty CHECK.
enabledboolean
last_fired_at, fire_countTelemetry for tuning.

RLS

Service-role bypass model: the API boundary applies authz in TypeScript per ADR-046, and PostgREST goes through the service role. RLS is enabled on all three tables with no user-facing policies — this is fail-closed against accidental exposure (a future PostgREST exposure can’t leak governance signals across orgs). Future tightening to user-driven RLS UPDATE policies is a follow-up once a shared cross-type org_members.user_id (TEXT) ↔ auth.uid() (UUID) policy helper is in place.

RPCs

governance_signal_emit

governance_signal_emit(
  p_scope TEXT,
  p_scope_id TEXT,
  p_source TEXT,
  p_pattern_type TEXT,
  p_severity TEXT,
  p_org_id TEXT,
  p_team_id UUID,
  p_agent_ids TEXT[],
  p_detail JSONB,
  p_source_ref JSONB,
  p_detected_by TEXT,
  p_expires_at TIMESTAMPTZ DEFAULT NULL
) RETURNS governance_signals
SECURITY DEFINER + service-role only. INSERT ... ON CONFLICT DO UPDATE on the open-dedup index — repeated cron emissions of the same condition refresh detected_at, severity, agent_ids, detail, source_ref on the existing open row instead of creating a new one.

governance_signal_acknowledge / _resolve / _dismiss

Operator state transitions. Each captures acknowledged_actor_role per ADR-046 and is SECURITY DEFINER so the API can invoke after applying RBAC in TypeScript.
governance_signal_acknowledge(p_id, p_actor, p_actor_role, p_action_taken DEFAULT NULL)
governance_signal_resolve(p_id, p_actor, p_actor_role, p_resolution_status, p_action_taken DEFAULT NULL)
governance_signal_dismiss(p_id, p_actor, p_actor_role, p_reason DEFAULT NULL)

REST endpoints

See api-reference/governance for full schemas. Quick map:
MethodPathRBAC
GET/v1/orgs/:org_id/governance/signalsany org member
GET/v1/teams/:team_id/governance/signalsany org member
GET/v1/agents/:agent_id/governance/signalsany org member
GET/v1/governance/signals/:idany org member of row’s org
POST/v1/governance/signals/:id/{acknowledge,resolve,dismiss}org_admin / org_owner
GET/v1/orgs/:org_id/governance/coverageany org member
*/v1/orgs/:org_id/governance/notification-destinations[/:id][/test]org_admin / org_owner
*/v1/orgs/:org_id/governance/escalation-rules[/:id]org_admin / org_owner

Webhook event taxonomy

EventFired when
governance.signal.firedNew row inserted (or open row coalesced).
governance.signal.acknowledged_acknowledge RPC.
governance.signal.resolved_resolve RPC.
governance.signal.dismissed_dismiss RPC.
governance.escalation.triggeredA rule’s predicate matched and dispatch fired.
Legacy aliases (kept 30 days post-cutover, removed at D+30):
  • sideband.coherence.fired → use governance.signal.fired filtered on payload.source == "sideband.coherence".
  • sideband.fault_line.fired → same.
  • sideband.fleet.fired → same.
  • drift.detected → use governance.signal.fired filtered on payload.source == "sideband.drift".
All HMAC-SHA256 signed (X-Mnemom-Signature: sha256=…) following the AAP webhook contract; subscribers should verify the signature before trusting the payload.

Naming convention discipline

source is closed, hierarchical, append-only — mirrors ADR-047 for pending_advisories.source. Adding a new value requires:
  1. ADR-048 amendment.
  2. Migration extending the CHECK constraint with ASSERT-after-DDL guard.
  3. Producer code (typically observer).
  4. Consumer-tolerance discipline (gateway / UI / CLI / SDKs).
  5. Posture-gating extension if the source is detector-driven.
Removing a source is forbidden. Deprecation is the only valid path.