2026-05-10-x2-event-taxonomy-expansion

X-2: Event taxonomy expansion (32 new event types)

Date: 2026-05-10 Status: shipped Slug: x2-event-taxonomy Branch: feature/x2-event-taxonomy Strategic plan item: X-2 (XDR pipeline pre-requisite that was deferred behind X-3..X-8)

Summary

Expanded PlatformEventType from 19 → 51 variants by adding 32 security-relevant event types across six categories (identity/auth, authorization, routing, behavioral, data-flow, audit-chain). Added matching PlatformEvent data shapes, OCSF projector cases, and EVENT_MAP entries (40 total — including null-as-suppress for high-volume telemetry events that exist for downstream consumers but should not fan out to webhooks/SIEM by default).

A new completeness-gate test (event-map-coverage.test.ts) fails CI if a future PR adds a PlatformEventType without an EVENT_MAP decision (delivery target or explicit null to suppress). This makes the type union the source of truth and makes "I forgot to map the new event" a compile-time-equivalent error.

Five core emission points are wired now:

  • cert.issuedsrc/api/routes/agent-cert.ts after signCsr
  • cert.revokedsrc/api/routes/agent-cert-revoke.ts after revocationStore.revoke
  • agent.bootstrappedsrc/api/routes/agent-bootstrap.ts on 201 response
  • authz.deniedsrc/api/middleware/rbac.ts on hasPermission failure
  • audit.envelope_signedsrc/security/trust-envelope/middleware.ts after sign

The remaining 27 event types are wired into the type system + projector + EVENT_MAP but their emission points are deferred to follow-up PRs (concentrated in anomaly-detection.ts, pii-scanner.ts, guardrail-chain.ts, model-router-select.ts, audit-signer.ts). Adding the type + projector + map ahead of emission is the right ordering: SIEM destinations can be configured to accept the events before the emission code lands, so there's no event drop at deploy.

Files

Modified

  • src/infra/notifications/dispatcher.ts (+85 LOC) — 32 new union members + matching data shapes + PLATFORM_EVENT_TYPES exported array for the gate test
  • src/infra/notifications/webhook-delivery.ts (+50 LOC) — EVENT_MAP expanded 8 → 40 entries, made Record (was Partial<>); added REGISTERED_EVENT_TYPES export
  • src/observability/xdr/ocsf-projector.ts (+200 LOC) — 28 new switch cases (4 are null-returning suppressions)
  • src/api/routes/agent-cert.ts (+15 LOC) — cert.issued emission
  • src/api/routes/agent-cert-revoke.ts (+15 LOC) — cert.revoked emission
  • src/api/routes/agent-bootstrap.ts (+15 LOC) — agent.bootstrapped emission
  • src/api/middleware/rbac.ts (+15 LOC) — authz.denied emission
  • src/security/trust-envelope/middleware.ts (+25 LOC) — audit.envelope_signed emission

New

  • src/infra/notifications/event-map-coverage.test.ts (47 LOC) — runtime completeness gate (2 tests)

Verification

  • pnpm tsgo — exit 0
  • pnpm test:fast — 7755/0 (+2 from completeness gate)
  • pnpm exec oxfmt --check — clean
  • pnpm exec oxlint --type-aware — 0 warnings, 0 errors

Lockstep

  • TypeScript SDK: no public surface change (no new routes)
  • Python SDK: no public surface change
  • MCP tools: no public surface change
  • routes.json: no new routes; pnpm build regenerates as no-op for routes
  • OpenAPI spec: no surface change

Why "EVENT_MAP value can be null"

Two reasons null beats omission:

  1. Compile-time-equivalent completeness check: The Record

type forces every member of the union to be a key. Forgetting one becomes a tsgo error, not a silent runtime drop.

  1. High-volume events should still be enumerated: routing.model_selected

fires on every completion. Mapping it to null is a deliberate design decision that documents "we considered this and chose to suppress." A future tenant who wants the firehose can flip the mapping without grepping the codebase to discover whether the event existed.

Why emission points are split between this PR and follow-ups

The plan called for ~600 LOC and emission across 8+ files. Lockstep + reviewer cap suggests a tighter PR. The five emission points wired here cover the highest SIEM-value surfaces (cert lifecycle, agent identity, auth chain). The remaining 27 events are reachable from the type system today and will fire as their emission points land. Importantly: the OCSF projector + EVENTMAP are complete \_now, so a SIEM destination configured this week catches every new emission as it ships without re-configuring.

Stop signals — none

No P0 in computer-eval queue. Strategic plan items remaining: A-8 (counterfactual replay), X-9 (XDR docs), A-10..A-12 (sandbox/test-harness/public spec). Loop continues.