Skip to content

Implement AI-side EventBridge handshake for email insight (PurposePath_Api #912 alignment) #302

Description

@mottych

Context

PurposePath_Api has completed and deployed the NotificationProcessor side for issue #912 with EventBridge-first AI kickoff + API fallback.

Backend references:

Goal

Implement the AI-side async handshake so email insight requests can be consumed via EventBridge and resolved via existing job-status API semantics, while preserving canonical payload semantics across transports.

Required Handshake Contract (AI side)

1) EventBridge kickoff consumption

Consume EventBridge entries with routing keys:

  • source = configured backend source (default purposepath.api)
  • detail-type = configured kickoff type (default ai.job.requested)
  • event bus = configured backend bus (default default)

Expected EventBridge detail payload shape (minimum):

{
  "eventId": "uuid",
  "occurredAtUtc": "2026-04-09T13:00:00.0000000Z",
  "sourceService": "PurposePath.NotificationProcessor.Lambda",
  "schemaVersion": "2.0",
  "correlationId": "corr-123",
  "idempotencyKey": "req-123:goal_created_email_insight:uuid",
  "retryAttempt": 0,
  "tenantId": "tenant-1",
  "userId": "user-1",
  "topicCategory": "email_insight",
  "topicId": "goal_created_email_insight",
  "eventSignal": "goal_created_email_insight",
  "locale": "en-US",
  "timezone": "UTC",
  "activityData": {
    "goal_id": "goal-1"
  },
  "authContext": {
    "serviceToken": "opaque-token",
    "expiresAtUtc": "2026-04-09T13:05:00Z",
    "issuer": "purposepath-api",
    "tokenType": "service_enrichment"
  },
  "jobId": "job-uuid",
  "eventType": "goal_created_email_insight",
  "kickoffTransport": "eventbridge"
}

2) Job status contract (must stay compatible)

Backend polls AI status endpoint and expects:

{
  "data": {
    "status": "completed|failed|cancelled|timed_out|running|queued",
    "result": {
      "schemaVersion": "1.0.0",
      "title": "...",
      "summary": "...",
      "blocks": [],
      "generationMeta": {}
    }
  }
}

Contract rules:

  • data.status is required.
  • data.result is required only when status=completed.
  • completed with missing/empty result is treated by backend as terminal non-success (no fallback).

3) API fallback compatibility

Backend fallback kickoff still calls POST /api/v1/ai/execute-async with the same canonical envelope semantics.
Response should remain:

{ "data": { "jobId": "job-uuid" } }

(data.job_id may be tolerated but canonical is data.jobId.)

AI Implementation Requirements

  1. Add EventBridge consumer for above routing keys and detail payload.
  2. Use detail.jobId as the authoritative async job identity.
  3. Persist and propagate correlation fields unchanged:
  • correlationId
  • idempotencyKey
  • eventId
  1. Ensure existing status API returns the exact wrapper shape expected by backend polling.
  2. Ensure completed status returns valid result object matching email insight schema expectations.
  3. Ensure enrichment requests use authContext.serviceToken as opaque bearer token.

Fallback/Behavior Expectations from backend side

Backend will fallback to API kickoff when EventBridge path cannot resolve quickly enough:

  • EventBridge publish failure
  • status request HTTP failure
  • status payload missing data.status
  • EventBridge await window timeout

Backend does NOT fallback on:

  • completed without payload
  • terminal failed/cancelled/timed_out status

Acceptance Criteria

  • EventBridge kickoff request is consumed and processed for email_insight topics.
  • Job lifecycle is visible via existing status endpoint using detail.jobId.
  • Completed jobs return valid data.result payload compatible with current backend parser.
  • correlationId/idempotencyKey/eventId preserved in telemetry and lifecycle records.
  • End-to-end verification with PurposePath_Api: EventBridge kickoff path resolves without fallback for at least one goal_created_email_insight case.
  • Fallback path remains operational and semantically identical.

Suggested Test Matrix

  • Happy path: EventBridge kickoff -> status completed -> payload returned.
  • EventBridge publish succeeds, status returns running/queued then completed.
  • Status returns missing data.status (backend should fallback).
  • Status returns terminal failed/cancelled/timed_out (backend should not fallback).
  • completed with malformed result (backend should treat as no payload).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions