SEIF Docs

Operational events and webhooks

Teams can integrate incidents, drift alerts and delivery decisions without granting an application release authority. The Registry retains an authenticated, environment-scoped operational feed; a separate worker forwards events to an explicitly configured webhook.

GET /v1/reliability/events?project=P&environment=E&cursor=0&limit=100 requires reliability.events, environment.view and trace.view. A scoped automation identity can hold these capabilities. Application identities cannot hold reliability.events or read the feed. Responses contain at most 200 events, an ascending cursor, hasMore, a prune watermark and a gap flag. Persist nextCursor only after processing every event up to it.

Types: context.incident.observed, context.consumption.mismatch, application.failure.reported, drift.alert.opened, drift.alert.acknowledged, drift.alert.resolved, promotion.blocked, promotion.approved, deployment.activated, deployment.failed. Structural signals and application reports have different names. A drift acknowledgement is not approval. deployment.activated describes activation readiness; it is not continuous health evidence.

Only identities, event type, scope, timestamp and allowlisted references are forwarded. No request/message content, test expectations, provider values or secret references enter the feed. Events are observations, never authority. Stable event ids allow receiver deduplication. Delivery is at least once; the feed retains the latest 10,000 events per environment, and does not fabricate events from older releases. A cursor older than the prune watermark receives gap: true; reconcile history before resetting it. A new cursor of zero reads available history only.

Runnable signed webhook worker

The standard-library Unix worker in examples/operations/webhook_worker.py needs Python 3, an automation credential in CONTEXT_EVENT_TOKEN and a distinct signing secret of at least 32 characters in WEBHOOK_SIGNING_SECRET. Load both from your secret manager; never put them in command-line arguments or tracked files.

python3 examples/operations/webhook_worker.py \
  --registry https://registry.example \
  --project support-agent-context --environment production \
  --destination https://operations.example/seif-events \
  --state /var/lib/seif-events/worker.sqlite

Use --once for a scheduled job. HTTP is refused unless --allow-local explicitly enables loopback testing. Both Registry and destination refuse redirects; secrets are never redirected to another host. The worker is the operator's integration boundary and uses the operator-configured destination; the Registry never makes outbound notification requests.

The worker sends the canonical JSON event with:

  • Idempotency-Key: stable event id.
  • X-SEIF-Timestamp: Unix seconds at dispatch.
  • X-SEIF-Signature: v1= plus HMAC-SHA256 of timestamp + "." + exact request body under the signing secret.

A receiver must verify the signature with constant-time comparison, reject timestamps outside its replay window (for example five minutes), and persist a deduplication record for the event id. A 2xx response acknowledges delivery. Do not acknowledge before durable processing/enqueueing. The HMAC authenticates transport; it does not turn a trace into signed SEIF Evidence.

The worker commits its SQLite cursor after each acknowledged event. Failures preserve the prior cursor, retry with bounded backoff and can redeliver after a crash between receipt and cursor commit. One worker owns each state file via an OS lock. Feed retention gaps fail explicitly. Destination failures produce content-free logs. Manage receiver deduplication, webhook secret rotation and worker/receiver retention as part of your integration.

Tests execute a local receiver, verify actual signatures, refuse an initial delivery, restart the worker and prove cursor recovery. No third-party notification service is contacted.