> ## 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.

# Pending Advisories Schema

> Wire format for pending_advisories rows + the closed source taxonomy and expansion contract.

`pending_advisories` is the unified cross-turn carryover surface. One table, one read point at the start of each runtime turn (`gateway/src/index.ts::injectPendingNudges`), multiple sources via a closed `source` enum spanning runtime + sideband + manual contexts.

This page documents the row shape every consumer can rely on (gateway, observer, dashboard, CLI, webhook subscribers) and the expansion contract for adding new sources.

## Row shape

```typescript theme={null}
interface PendingAdvisory {
  id: string;                    // pa-<12 hex chars>
  agent_id: string;              // mnm-<uuid>
  session_id: string | null;     // null for sideband.* (cross-session); set for runtime.*
  text: string;                  // injected nudge_content; bracket-wrapped
  source: SourceValue;           // closed enum (see §"Source taxonomy")
  source_ref: SourceRef;         // JSONB; shape per source (see §"source_ref shapes")
  status: "pending" | "consumed" | "expired";
  created_at: string;            // ISO-8601 UTC
  consumed_at: string | null;    // ISO-8601 UTC; set when gateway injects
  expires_at: string;            // ISO-8601 UTC; default created_at + 24h
}
```

**TTL.** Default 24 hours. Configurable platform-wide by Mnemom platform admins; not configurable per-org or per-agent.

**Status transitions.** Always forward: `pending → consumed` (gateway injected on a turn) or `pending → expired` (TTL elapsed without injection). No revivals.

## Source taxonomy

Closed, hierarchical, append-only enum. Adding a new value requires the [expansion recipe](#expansion-contract) (schema amendment + migration + producer + consumer-tolerance).

| Context     | Producer                                                    | Examples                                                     |
| ----------- | ----------------------------------------------------------- | ------------------------------------------------------------ |
| `runtime.*` | `gateway/src/index.ts` (same-turn intervention bookkeeping) | `runtime.front_door.nudge`, `runtime.back_door.modification` |
| `manual.*`  | mnemom-api admin handlers (human-attached)                  | `manual.admin`                                               |

<Warning>
  **Surface-separation invariant.** As of 2026-05-07, `sideband.*` sources are no longer accepted into `pending_advisories`. Cron-driven, fleet-shaped observations (the four legacy `sideband.drift` / `sideband.coherence` / `sideband.fault_line` / `sideband.fleet` rows) now write to the operator-actionable [`governance_signals`](/specifications/governance-signals-schema) table, never to `pending_advisories`. A `NOT VALID` CHECK constraint on `pending_advisories.source` rejects new sideband.\* writes; pre-cutover historical rows remain queryable for compliance attestation but were marked `status='expired'` by migration 193.
</Warning>

### Current ratified values (post-cutover)

| Source                           | Producer                        | Posture-gated | Webhook event                     |
| -------------------------------- | ------------------------------- | ------------- | --------------------------------- |
| `runtime.front_door.nudge`       | gateway (front-door handler)    | No            | (none)                            |
| `runtime.front_door.enforce`     | gateway (front-door handler)    | No            | (none)                            |
| `runtime.inside.autonomy.nudge`  | gateway (CLPI handler)          | No            | (none)                            |
| `runtime.inside.integrity.nudge` | gateway (AIP handler)           | No            | (none)                            |
| `runtime.back_door.modification` | gateway (back-door handler)     | No            | (none)                            |
| `manual.admin`                   | mnemom-api admin attach handler | No            | future `manual.advisory_attached` |

`sideband.drift` / `sideband.coherence` / `sideband.fault_line` / `sideband.fleet` previously appeared here. They moved to [`governance_signals`](/specifications/governance-signals-schema) with the 2026-05-07 cutover; the four legacy `sideband.*.fired` and `drift.detected` webhook event names continue to fire for D+30 backwards-compat through 2026-06-07.

## `source_ref` shapes

JSONB envelope keyed off `source`. Conventions:

* Every `runtime.*` row carries `{checkpoint_id: string, mode_at_fire: "off"|"observe"|"nudge"|"enforce"}`
* Every `manual.*` row carries `{actor_user_id: string, attached_at: string, note?: string}`

For `sideband.*` `source_ref` shapes, see the [`governance_signals` table](/specifications/governance-signals-schema#governance_signals); those observations write to the operator-actionable surface, not to this table.

### `runtime.*` — `source_ref`

```json theme={null}
{
  "checkpoint_id": "ckpt-92e1d8b3",
  "mode_at_fire": "nudge"
}
```

`checkpoint_id` references the `integrity_checkpoints` row created on the same turn. `mode_at_fire` is the agent's effective mode at intervention time (post-cascade, pre-fire).

### `manual.admin` — `source_ref`

```json theme={null}
{
  "actor_user_id": "user-a3f29c1e",
  "attached_at": "2026-05-04T15:32:00Z",
  "note": "Customer support attached after escalation #47291"
}
```

## `nudge_content` format

Every advisory's `text` follows a stable wrapper:

```
[Mnemom advisory: <one-sentence finding>. <one-sentence recommendation>.]
```

The bracket wrapper enables the gateway's user-visible-explanation guarantee to detect that an injection happened. Producers MUST keep the wrapper; if the wrapper is missing on a delivered turn, the gateway suffix-injects its own marker `[Mnemom: <intervention summary>]`.

## `concerns_summary` format

Short structured headline (≤80 chars) used for telemetry, dashboard display, and CLI list output. Convention: `<axis>: <short outcome>`.

| Source         | Example                      |
| -------------- | ---------------------------- |
| `runtime.*`    | `<checkpoint>: <mode>-fired` |
| `manual.admin` | `Manual: <one-line note>`    |

## Read endpoints

| Endpoint                                 | Auth              | Returns                                                                    |
| ---------------------------------------- | ----------------- | -------------------------------------------------------------------------- |
| `GET /v1/agents/:id/sideband-advisories` | user (org member) | All `sideband.*` advisories for one agent (default last 50, max 200).      |
| `GET /v1/teams/:id/sideband-advisories`  | user (org member) | All `sideband.*` advisories for member agents (default last 100, max 500). |
| `GET /v1/teams/:id/sideband-coverage`    | user (org member) | 30-day per-axis sweep summary + raw rows.                                  |

Filters (all optional, on the agent + team listing endpoints):

* `?since=<ISO-8601>` — only advisories created after this timestamp
* `?limit=<n>` — page size (default 50/100, max 200/500)

Service-key paths used by the observer cron (not customer-facing — gated behind `X-Service-Key`, exposed under an internal namespace that does not appear in the customer OpenAPI):

| Operation                             | Auth                      | Purpose                                          |
| ------------------------------------- | ------------------------- | ------------------------------------------------ |
| Active-teams enumeration              | `X-Service-Key`           | Observer cron: enumerate teams to sweep          |
| Sideband sweep heartbeat              | `X-Service-Key`           | Observer heartbeat: UPSERT per-sweep log row     |
| `GET /v1/teams/:id/effective-posture` | `X-Service-Key` (or user) | Observer posture read (customer-facing endpoint) |

## Expansion contract

### Adding a new source

To add a new value to `source`, a single PR train MUST land all of:

1. **Schema amendment** to the source taxonomy adding the value with its producer, consumer responsibilities, and `source_ref` shape.
2. **Migration** (`ALTER TABLE pending_advisories DROP CONSTRAINT … ADD CONSTRAINT … CHECK (source IN (…))`) appending the new value. Migration MUST use the post-DDL `pg_proc.prosrc` ASSERT pattern from `mnemom-api/database/migrations/158_*.sql`.
3. **Producer code** that writes rows with the new source — fire-and-forget, never throws on insert failure.
4. **Consumer-tolerance discipline** — `gateway/src/index.ts::injectPendingNudges` MUST already render any unknown source as a generic advisory (the current code does this; it doesn't filter on source). Future consumers (dashboard filter chips, CLI `--source`, webhook event types) MUST tolerate the value via either pre-registration or graceful unknown-source fallback.
5. **`source_ref` JSONB shape** documented per source on this page.
6. **For `sideband.*` only** — extend `PostureBody.sideband` with the corresponding axis configuration (`enabled`, `cadence_seconds`, `severity_floor` or `fire_on.*`, `severity_on_fire`). The Posture is the policy surface; new sideband sources without posture-body fields are forbidden.

### Removing a source

**Forbidden.** Removing a source breaks compliance attestation (historical advisories with that source value become un-renderable) and breaks deserialization for any consumer holding archived rows. Deprecation is the only valid path: stop producing the source, document the deprecation, but leave the CHECK constraint accepting the value forever.

## Webhook events

Each source's webhook event name follows `<source>.fired` — with one documented carve-out: `sideband.drift` keeps its legacy `drift.detected` name. Subscribers receive the standard webhook envelope:

```json theme={null}
{
  "id": "wh-evt-1f2a8e9c",
  "type": "sideband.coherence.fired",
  "created_at": "2026-05-04T15:32:00Z",
  "account_id": "acct-acme-banking",
  "data": {
    "team_id": "tm-acme-banking",
    "reasons": ["pairwise_governance_floor=0.42 < 0.5"],
    "pairwise_governance_floor": 0.42,
    "conflict_edge_count": 3,
    "outlier_agent_ids": ["agt-monitor-3"],
    "severity": "medium",
    "detected_at": "2026-05-04T15:32:00Z"
  }
}
```

See [Subscribing to Safe House webhooks](/guides/safe-house-webhooks) for the full subscription + signature-verification flow.

## See also

* [Sideband detection](/concepts/sideband-detection) — concept overview and the four-source taxonomy
* [Trust Posture](/concepts/trust-posture) — the policy surface that drives `sideband.*` thresholds
* [Compliance attestation foundation](/guides/compliance-attestation-foundation) — how `sideband_sweep_log` + posture-versioned snapshots feed control mappings
