Track B Phase 3 (CR-7) — governance event types on the live feed

2026-06-21

governance-dashboardcapability-grantsscope-enforcementsse

LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: ["GET /auth/events — extended event vocabulary (no new route)"] sdk_methods_updated: ["none"] mcp_tools_updated: ["none"] ---

What We Built

The dashboard's SSE stream (GET /auth/events) previously carried only operational types (request | budget | circuit | security | cache | ping). CR-7 adds the governance vocabulary the Phase 3 LIVE ● feed subscribes to: scope_denial, would_deny, grant_issued, grant_revoked, chain_break. Each is a real decision or authority mutation with a flat, small payload ({ principal, requestId?, grantId?, source?, requested?, reason?, ts }), emitted at the chokepoint that already exists:

  • scope_denial / would_deny ride recordAuthorizationDenial — the single point every enforced denial and warn-mode would-deny already passes through. The event fires the instant the decision is made, independent of whether the durable chain write succeeds (the decision already happened; enforcement is unaffected).
  • grant_issued / grant_revoked ride recordGrantLifecycle — the shared hook for issue/attenuate/revoke across both the apiKey /v1/grants and JWT /auth/grants surfaces, so one emission point covers them all.
  • chain_break is declared and emittable; its producer is the audit-verify path (a follow-on Phase 3 slice).

Why It Matters

Phase 1's evidence view was honest but static — an operator refreshed to see what happened. CR-7 makes governance _live_: a scope denial, a would-deny preview, or a break-glass revoke appears on the operator's feed the moment it occurs, with the principal and reason attached. It's the substrate the would-deny preview and the Ledger's live tail are built on.

How It Works

emitGovernanceEvent(tenantId, type, payload) (in sse-broadcaster.ts) stamps ts and fans out through the existing SSEBroadcaster — fire-and-forget, swallowing its own errors so the live feed can never affect the act it describes. Clients filter via ?types=scope_denial,grant_revoked,…; the VALID_TYPES allowlist in the /auth/events capability was extended in lockstep so the new types are subscribable.

The Numbers

  • 5 governance event types; 3 new tests (delivery + ts stamping, type-filter drop, formatSSE line).
  • 9,029 unit tests pass; pnpm check green. No new route, no SDK/MCP surface — an additive event vocabulary on an existing stream.

Competitive Edge

Plenty of gateways stream request logs. Streaming _governance decisions_ — "agent X was denied tool:shell, here's why" and "grant g9 was just revoked, cascade" — as first-class typed events is the evidence plane in real time.

Lockstep Checklist

  • [x] API Routes: /auth/events vocabulary extended; emission wired at recordAuthorizationDenial + recordGrantLifecycle.
  • [x] TS/Python SDK: none.
  • [x] MCP Schemas: none.
  • [x] Tests: 3 new broadcaster tests; full suite green.

Remaining (Phase 3)

Frontend consumption (the LIVE ● feed wiring the new types into the Ledger/Grants surfaces), the chain-verify badge (CR-1, against the existing /auth/governance/audit/verify), chain_break emission from the verify path, the would-deny preview UI (CR-3), and effective-state badges (CR-2/CR-5). Phase 4 (Plans) after.