Skip to content

Commit 32295aa

Browse files
docs(governance): concept + schema + guides + changelog (ADR-048 PR12)
Mintlify documentation for governance_signals — the operator-actionable observation surface introduced in ADR-048. New pages --------- - concepts/governance-signals.mdx Headline doc. Explains operator-vs-agent layering, the four sources, the three operator surfaces (UI/webhook/REST), the operator workflow (open → ack → resolve/dismiss/expired), notification destinations, and the §I15 charter invariant. - specifications/governance-signals-schema.mdx Table layout, RPC surface, webhook event taxonomy, RLS model. Cross- references ADR-046 (actor_role), ADR-047 (source-enum discipline), ADR-048 (layering). - guides/operating-governance-signals.mdx Operator runbook: daily ack/resolve/dismiss flow, destinations CRUD (Slack/email/PagerDuty/webhook with CLI examples), escalation rules with rate-gating, coverage rollup, audit trail. - guides/sovereign-agent-composition.mdx Application-side worked pattern. When to use it, when NOT to use it (counter-example), TS code samples, application-side role config (NOT in the alignment card), filter policy, ack-from-the-agent's-voice pattern. Polis Wintermute as canonical reference. Updated ------- - concepts/sideband-detection.mdx — cutover note pointing readers at governance-signals; clarifies that detection logic is unchanged, only delivery surface moved. - docs.json sidebar — three new entries (concepts, specifications, guides ×2). - changelog.mdx — full release entry with the architectural carve, the triggering symptom (Wintermute 2× paragraph), the cutover scope, every shipped artifact across mnemom-api / mnemom-platform / aap / aip / website / cli. Mintlify EN-only per T1-3.1 deferral. EFIGS for the dashboard governance-signals namespace shipped in mnemom-website#363 (PR11); docs.mnemom.ai stays English. The for-agents JSON contract (T7-2) at docs.mnemom.ai/for-agents/governance-signals.json is filed as a follow-on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 84f9b1c commit 32295aa

7 files changed

Lines changed: 694 additions & 1 deletion

File tree

changelog.mdx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,33 @@ Track changes across the Mnemom ecosystem -- protocols, SDKs, infrastructure, an
1111

1212
---
1313

14+
## Governance signals — operator-actionable observation surface (ADR-048)
15+
<sub>May 2026</sub>
16+
17+
Carved the architectural boundary between **agent-actionable carryover** (`pending_advisories`, runtime.* + manual.* sources) and **operator-actionable observation** (new `governance_signals` table, `sideband.*` + future `protection.*` / `posture.*` sources). Application-side composers (e.g., Polis for sovereign-CTO agents like Wintermute) own the edge case of folding a fleet signal into a sovereign agent's prompt — the platform never auto-injects.
18+
19+
The triggering symptom: a sovereign agent receiving the same `cluster_partition` paragraph 2× per turn for weeks. Root cause: cron-driven, fleet-shaped observations were mis-layered into per-turn agent context. ADR-048 fixed the layering at the schema, producer, and consumer layers simultaneously.
20+
21+
**What's new:**
22+
23+
- New `governance_signals` table with partial-unique open-dedup index (kills the duplicate-emission symptom at the WRITE layer).
24+
- New REST surface at `/v1/{orgs,teams,agents}/.../governance/signals` plus state-transition endpoints.
25+
- New webhook event family `governance.signal.{fired,acknowledged,resolved,dismissed}` + `governance.escalation.triggered`. Legacy aliases (`sideband.*.fired`, `drift.detected`) kept for 30 days post-cutover.
26+
- New notification destinations: Slack incoming-webhook, email (Resend), PagerDuty Events API v2, generic HMAC-signed webhook. Per-org configurable + filterable + rule-driven.
27+
- New escalation rule engine with rate-based gating (`threshold_count` + `window_minutes`).
28+
- New UI at team + agent scope (`/dashboard/teams/:teamId/governance` + `/dashboard/agents/:uuid/governance`).
29+
- `mnemom governance` CLI subcommand group: `signals`, `destinations`, `rules`.
30+
- `@mnemom/agent-alignment-protocol@1.1.0` ships TypeScript types + sovereign-composer example.
31+
- `@mnemom/agent-integrity-protocol@1.1.0` adds optional `triggering_governance_signal_id` to `IntegritySignal`.
32+
33+
**Cutover:** observer writers redirected (mnemom-platform#246), gateway reader narrowed (mnemom-platform#247). Pre-cutover `pending_advisories` rows for `sideband.*` TTL out within 24 hours.
34+
35+
**Charter invariant** (`safe-house-hardening/validation-charter.md` §I15): operator observations never reach an agent's prompt; agent advisories never reach the operator alert rail. Asserted by the harness.
36+
37+
See [governance signals](/concepts/governance-signals), [schema](/specifications/governance-signals-schema), [operator runbook](/guides/operating-governance-signals), [sovereign-agent composition](/guides/sovereign-agent-composition).
38+
39+
---
40+
1441
## Agent ID format update — `mnm-{uuid_v4}`
1542
<sub>April 2026</sub>
1643

concepts/governance-signals.mdx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
title: "Governance signals"
3+
description: "Operator-actionable observations from Mnemom's platform detectors — fleet drift, value fault lines, coherence drops, behavior drift. Surfaced to operators (UI, webhook, REST) and to application composers, never auto-injected into agent prompts."
4+
sidebarTitle: "Governance signals"
5+
icon: "siren"
6+
---
7+
8+
# Governance signals
9+
10+
**Governance signals** are operator-actionable observations produced by Mnemom platform detectors. They surface fleet-shaped concerns — coherence drift across a team, value fault lines between agents, fleet topology changes, per-agent behavior drift — that an *operator* (CISO, org admin, team admin, on-call SRE) needs to see and act on.
11+
12+
They are deliberately distinct from the [per-turn advisories](/concepts/safe-house) that the gateway injects into an agent's next prompt. The architectural commitment, ratified in [ADR-048](https://github.com/mnemom/scale/blob/main/decisions/ADR-048-governance-signals-layering.md), is:
13+
14+
> **Operator observations never reach an agent's prompt; agent advisories never reach the operator alert rail.**
15+
16+
If a non-sovereign agent is told "Recalibrate fleet alignment before the next response," it has no team-management authority, no acknowledgment surface, and no remediation it can perform from inside its own LLM call. The signal is real and important — but the recipient is wrong. Governance signals fix that mis-layering.
17+
18+
## What gets surfaced
19+
20+
| Source | Detector | What it catches | Acts at |
21+
|---|---|---|---|
22+
| `sideband.drift` | Per-agent drift | An agent's behavior diverging from declared alignment | Per agent |
23+
| `sideband.coherence` | Team coherence | Pairwise governance scores below threshold; conflict edges; outlier agents | Per team |
24+
| `sideband.fault_line` | Value fault lines | A value dimension splits the team into agents-declaring vs agents-missing vs agents-conflicting | Per team |
25+
| `sideband.fleet` | Fleet topology | Cluster partitions, weak-pair score floors, fleet outliers | Per team |
26+
27+
Future `protection.*` and `posture.*` sources will land additively via [ADR-048 amendment](https://github.com/mnemom/scale/blob/main/decisions/ADR-048-governance-signals-layering.md#section-8).
28+
29+
## Surfaces, not injections
30+
31+
A governance signal lives in **three operator surfaces** simultaneously:
32+
33+
1. **Web UI** at `app.mnemom.ai/dashboard/teams/{teamId}/governance` (and per-agent at `…/dashboard/agents/{uuid}/governance`). Filterable list, severity badges, ack/resolve/dismiss workflow.
34+
2. **Webhook** events: `governance.signal.fired`, `governance.signal.acknowledged`, `governance.signal.resolved`, `governance.signal.dismissed`, `governance.escalation.triggered`. HMAC-SHA256 signed POSTs (`X-Mnemom-Signature: sha256=…`) following the AAP webhook contract.
35+
3. **REST API**: `GET /v1/orgs/:org/governance/signals`, `GET /v1/teams/:team/governance/signals`, `GET /v1/agents/:agent/governance/signals`, plus state-transition endpoints. See [Governance Signals Schema](/specifications/governance-signals-schema).
36+
37+
The platform **never** injects governance signals into an agent's LLM request. That decision lives entirely in your application, if you have a sovereign-CTO-shaped agent who legitimately can act on fleet-level signals (e.g., a fleet orchestrator agent with reorg tools). See [Sovereign-agent composition](/guides/sovereign-agent-composition) for the worked pattern.
38+
39+
## Operator workflow
40+
41+
A signal moves through this lifecycle:
42+
43+
```
44+
open → acknowledged → resolved
45+
↘ ↗
46+
dismissed
47+
48+
expired (TTL)
49+
```
50+
51+
- **`open`** — fresh detection. Notification rail (Slack, email, PagerDuty, generic webhook) routes per your [escalation rules](/guides/operating-governance-signals#escalation-rules).
52+
- **`acknowledged`** — an org admin / org owner / team admin has confirmed receipt. Captures `acknowledged_actor_role` per [ADR-046](https://github.com/mnemom/scale/blob/main/decisions/ADR-046-audit-actor-model.md) audit-actor model.
53+
- **`resolved`** — closed with a `resolution_status` (`action_taken` / `wont_fix` / `duplicate` / `false_positive` / `self_resolved`) and optional `action_taken` note.
54+
- **`dismissed`** — operator marked as not actionable (noise, redundant).
55+
- **`expired`** — TTL elapsed without operator action; configurable per posture, default 30 days.
56+
57+
The schema's partial unique index on `(scope, scope_id, source, pattern_type) WHERE status='open'` makes detection idempotent: repeated cron emissions of the same condition refresh the open row in place rather than stacking. This is the architectural fix to the symptom that triggered this work — a sovereign agent receiving the same `cluster_partition` paragraph 2× per turn for weeks.
58+
59+
## Notification destinations
60+
61+
Each org configures destinations independently:
62+
63+
- **`webhook`** — generic HMAC-signed POST to a URL of your choice. Mirrors AAP webhook contract.
64+
- **`slack`** — incoming-webhook POST with [Block Kit](https://api.slack.com/block-kit) payload. Severity-color border, action button to "Acknowledge in dashboard."
65+
- **`email`** — Resend-backed HTML + plaintext.
66+
- **`pagerduty`** — Events API v2 with stable `dedup_key` so coalesced detections don't duplicate incidents.
67+
68+
A destination's `filter` narrows what it receives (sources, severities, scopes, pattern_types). [Escalation rules](/guides/operating-governance-signals#escalation-rules) bind a predicate to a list of destination IDs and support rate-based gating (`threshold_count` + `window_minutes`) for "fire only if N matching signals occurred in M minutes."
69+
70+
Test a destination from the CLI:
71+
72+
```bash
73+
mnemom governance destinations test <destination_id> --org <org_id>
74+
```
75+
76+
This sends a synthetic signal through the channel only (bypasses rules) and records `last_tested_at` / `last_test_status` on the destination.
77+
78+
## Charter invariant
79+
80+
The [Safe House Hardening](https://github.com/mnemom/safe-house-hardening) validation charter ratifies §I15 — surface separation invariant — asserted by the harness:
81+
82+
1. End-to-end fixtures that provoke each `governance_signals` source and assert the agent's prompt is byte-clean.
83+
2. Telemetry that production gateway requests over a 30-day rolling window write zero `pending_advisories` rows whose `source LIKE 'sideband.%'`.
84+
85+
The harness gate is binding for `T1-4` (CI gate) closure post-cutover.
86+
87+
## Related
88+
89+
- [Sideband detection](/concepts/sideband-detection) — the detector layer (unchanged; only the delivery surface moved).
90+
- [Governance Signals Schema](/specifications/governance-signals-schema) — table layout, RPCs, RLS.
91+
- [Operating governance signals](/guides/operating-governance-signals) — operator runbook for ack/resolve/dismiss + destinations + rules.
92+
- [Sovereign-agent composition](/guides/sovereign-agent-composition) — application-side pattern for opting sovereign agents into governance-signal context.
93+
- [ADR-048](https://github.com/mnemom/scale/blob/main/decisions/ADR-048-governance-signals-layering.md) — the architectural decision.

concepts/sideband-detection.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ Four detector axes share this surface:
1818
| `sideband.fault_line` | Fault-line analysis | A specific value dimension splits the team — some agents declare it, others miss it, others list it as a conflict. |
1919
| `sideband.fleet` | Fleet patterns | The team partitions into incompatible clusters, the worst pair drops below threshold, or outliers emerge under cluster topology. |
2020

21-
All four write to the same carryover table (`pending_advisories`, per [ADR-040](/specifications/pending-advisories-schema)) and the gateway reads from a single inject point (`injectPendingNudges`) when the agent's next request arrives.
21+
All four write to [`governance_signals`](/concepts/governance-signals) (per [ADR-048](https://github.com/mnemom/scale/blob/main/decisions/ADR-048-governance-signals-layering.md)) — the operator-actionable observation surface. Surfaced via UI dashboard, webhook (`governance.signal.fired`), REST, and CLI. **Not** auto-injected into agent prompts; that architectural mis-layering is what ADR-048 corrected. See [governance signals](/concepts/governance-signals) for the full layering and operator workflow.
22+
23+
<Note>
24+
**Cutover note (2026-05-07):** Detection logic on this page (cadence, fire conditions, fan-out fields) is unchanged. Only the *delivery surface* moved: from `pending_advisories` (which the gateway injected into agent prompts) to `governance_signals` (operator-facing). Pre-cutover `pending_advisories` rows with `source LIKE 'sideband.%'` will TTL out within 24 hours of the gateway-reader narrowing in mnemom-platform#247.
25+
</Note>
2226

2327
## Why sideband
2428

docs.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"concepts/value-coherence",
5656
"concepts/fleet-coherence",
5757
"concepts/sideband-detection",
58+
"concepts/governance-signals",
5859
"concepts/reputation-scores",
5960
"concepts/team-reputation",
6061
"concepts/risk-assessment",
@@ -88,6 +89,7 @@
8889
"specifications/team-template-schemas",
8990
"specifications/trust-posture-schema",
9091
"specifications/pending-advisories-schema",
92+
"specifications/governance-signals-schema",
9193
"specifications/otel-attributes",
9294
"specifications/policy-dsl"
9395
]
@@ -124,6 +126,8 @@
124126
"guides/api-versioning",
125127
"guides/observability",
126128
"guides/sideband-detection",
129+
"guides/operating-governance-signals",
130+
"guides/sovereign-agent-composition",
127131
"guides/posture-cloning",
128132
"guides/compliance-attestation-foundation",
129133
"guides/multi-agent-setup",
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
title: "Operating governance signals"
3+
description: "Operator runbook for ack/resolve/dismiss workflow, notification destinations (Slack/email/PagerDuty/webhook), and escalation rules."
4+
sidebarTitle: "Operating governance signals"
5+
icon: "list-check"
6+
---
7+
8+
# Operating governance signals
9+
10+
[Governance signals](/concepts/governance-signals) are observations operators see and act on. This guide walks through the runbook.
11+
12+
## Daily flow
13+
14+
1. **Triage** the open queue at `app.mnemom.ai/dashboard/teams/{teamId}/governance` (or via `mnemom governance signals list --team <id> --status open`).
15+
2. **Acknowledge** signals you're investigating. Records `acknowledged_actor_role` per [ADR-046](https://github.com/mnemom/scale/blob/main/decisions/ADR-046-audit-actor-model.md) — captures whether you acted as `org_admin`, `team_admin`, etc.
16+
3. **Resolve** with a `resolution_status`:
17+
- `action_taken` — you (or a sovereign agent) made changes (rebalanced team, refreshed cards, …).
18+
- `wont_fix` — known noise or out of scope.
19+
- `duplicate` — same root cause as another signal.
20+
- `false_positive` — detector misfire (file a debt item).
21+
- `self_resolved` — the underlying condition cleared itself before you acted.
22+
4. **Dismiss** for noise: the signal is acknowledged but no action is needed and no resolution category applies cleanly.
23+
24+
CLI:
25+
26+
```bash
27+
mnemom governance signals list --team team-uuid-here --status open
28+
mnemom governance signals show gs-abc123def456
29+
mnemom governance signals ack gs-abc123def456 --action "investigating cluster shape"
30+
mnemom governance signals resolve gs-abc123def456 \
31+
--status action_taken \
32+
--action "rebalanced team — moved agent-X to fleet-B"
33+
```
34+
35+
## Notification destinations
36+
37+
Configure where signals route off-platform. Each destination is one channel binding for an org.
38+
39+
### Slack
40+
41+
```bash
42+
mnemom governance destinations add \
43+
--org org-id \
44+
--channel slack \
45+
--name "#sec-alerts" \
46+
--config '{"url":"https://hooks.slack.com/services/T.../B.../..."}'
47+
```
48+
49+
Block Kit payload with severity-color border, action button "Acknowledge in dashboard."
50+
51+
### Email
52+
53+
```bash
54+
mnemom governance destinations add \
55+
--org org-id \
56+
--channel email \
57+
--name "Security on-call" \
58+
--config '{"to":["security-oncall@yourco.com"],"from":"governance@yourco.com"}'
59+
```
60+
61+
Resend-backed HTML + plaintext.
62+
63+
### PagerDuty
64+
65+
```bash
66+
mnemom governance destinations add \
67+
--org org-id \
68+
--channel pagerduty \
69+
--name "Critical on-call" \
70+
--config '{"routing_key":"R1234567890ABCDEF"}'
71+
```
72+
73+
Events API v2 with stable `dedup_key` (`governance-signal-{id}`) — coalesced detections don't create duplicate incidents.
74+
75+
### Generic webhook
76+
77+
```bash
78+
mnemom governance destinations add \
79+
--org org-id \
80+
--channel webhook \
81+
--name "Internal SOC pipeline" \
82+
--config '{"url":"https://soc.internal/governance","signing_secret":"<32+ bytes>"}'
83+
```
84+
85+
HMAC-SHA256 signed POST. Verify the signature server-side before trusting the payload.
86+
87+
### Test before you trust
88+
89+
Every destination supports a synthetic test signal:
90+
91+
```bash
92+
mnemom governance destinations test <destination_id> --org <org_id>
93+
```
94+
95+
This sends a test signal through the channel only (bypasses rules) and records `last_tested_at` / `last_test_status` on the destination row. The dashboard surfaces the result inline.
96+
97+
## Filter narrowing
98+
99+
Each destination has an optional `filter` that AND-folds with the matching escalation rule's predicate. Useful for "only critical to PagerDuty, everything else to Slack":
100+
101+
```bash
102+
# PagerDuty: critical only
103+
mnemom governance destinations add --org org-id --channel pagerduty \
104+
--config '...' --filter '{"severities":["critical"]}'
105+
106+
# Slack: warn + high (PagerDuty handles critical separately)
107+
mnemom governance destinations add --org org-id --channel slack \
108+
--config '...' --filter '{"severities":["warn","high"]}'
109+
```
110+
111+
Filter keys: `sources`, `severities`, `scopes`, `pattern_types`. Absent key = match-all on that dimension.
112+
113+
## Escalation rules
114+
115+
Rules bind a predicate to a list of destinations. When an inserted signal matches the predicate, the dispatcher routes to the rule's destinations (intersected with each destination's filter).
116+
117+
```bash
118+
mnemom governance rules add \
119+
--org org-id \
120+
--name "fleet-critical-pageout" \
121+
--predicate '{"source":"sideband.fleet","severity_min":"high"}' \
122+
--destinations dest-pagerduty-id,dest-slack-id
123+
```
124+
125+
Predicate keys (AND-folded):
126+
127+
- `source` — exact source match.
128+
- `pattern_type` — exact pattern_type match.
129+
- `severity_min` / `severity_max` — bound on severity.
130+
- `scope` — exact scope match.
131+
- `team_id` — narrow to one team.
132+
- `threshold_count` + `window_minutes`**rate-based gating**: fire only if ≥ N matching signals occurred in M minutes.
133+
134+
### Rate-gating example
135+
136+
"Page on-call only if 3+ critical signals fire in 5 minutes":
137+
138+
```bash
139+
mnemom governance rules add \
140+
--org org-id \
141+
--name "critical-burst-pageout" \
142+
--predicate '{"severity_min":"critical","threshold_count":3,"window_minutes":5}' \
143+
--destinations dest-pagerduty-id
144+
```
145+
146+
### Dedup across rules
147+
148+
If two rules both route to the same destination, the dispatcher dedups — one Slack message per signal, not two. Each contributing rule's `fire_count` and `last_fired_at` still get bumped.
149+
150+
## Coverage rollup
151+
152+
`GET /v1/orgs/:org_id/governance/coverage?days=30` returns a per-(source, severity) aggregate over the window:
153+
154+
```bash
155+
curl -H "Authorization: Bearer $TOKEN" \
156+
"https://api.mnemom.ai/v1/orgs/org-id/governance/coverage?days=30" | jq
157+
```
158+
159+
```json
160+
{
161+
"org_id": "org-id",
162+
"since": "2026-04-07T00:00:00Z",
163+
"days": 30,
164+
"total_signals": 47,
165+
"by_source_severity": [
166+
{ "source": "sideband.fleet", "severity": "high", "total": 12, "open": 0 },
167+
{ "source": "sideband.coherence", "severity": "warn", "total": 8, "open": 2 },
168+
{ "source": "sideband.drift", "severity": "warn", "total": 27, "open": 4 }
169+
]
170+
}
171+
```
172+
173+
Use this for compliance evidence (signals were detected and operators responded), and as input for tuning your escalation rules — sources with high `open` ratios may need ack-process tightening; sources with high volume may want filter narrowing on noisy destinations.
174+
175+
## Auditing
176+
177+
Every state transition records `acknowledged_actor_role` (who acted, in what capacity) per [ADR-046](https://github.com/mnemom/scale/blob/main/decisions/ADR-046-audit-actor-model.md). `resolution_status` + `action_taken` provide the prose audit trail. Combine with [`governance_audit_log`](/specifications/governance-audit-log) for full SOC2-shaped reconstruction.
178+
179+
## Related
180+
181+
- [Governance signals concept](/concepts/governance-signals).
182+
- [Governance Signals Schema](/specifications/governance-signals-schema).
183+
- [Sovereign-agent composition](/guides/sovereign-agent-composition) — application-side pattern when you have a sovereign-CTO-shaped agent.

0 commit comments

Comments
 (0)