SSE caseload filtering (op-infra Step 9 follow-up)

Context

Op-infra Step 9 shipped SSE infrastructure on canopy-web (single AMQP queue + tokio broadcast + browser EventSource). The htmx-sse extension half closed in MR !188 (2026-05-04). One scope item remains: caseload filtering.

Caseload-based filtering (plan §9.2)

The plan calls for filtering by the worker's assigned caseload. Today the SSE handler broadcasts every routing-key-matched event to every connected worker. This is fine for a small worker pool, but at scale it leaks events about cases the worker isn't responsible for.

Blocker: there is no caseload-membership store yet. Adding one is a larger design (per-worker assignment model, supervisor reassignment workflow, ownership transitions) outside Step 9's scope.

When that lands, the SSE handler reads the worker's caseload from session and filters envelope payloads server-side before sending to the per-connection receiver. The broadcast hub stays single-shard.

Acceptance criteria

  1. Caseload-filtering: handler reads worker's caseload from session, filters envelope payloads before send. Gated on broader case-management work.

Resolved sub-items

  • htmx-sse extension wiring — closed in MR !188 (2026-05-04). `htmx-sse.min.js` v2.2.4 vendored under `services/canopy-web/static/vendor/`. Base template uses ``. Hand-rolled `EventSource` IIFE in `canopy-web.js` retired (zero consumers). Page templates can now use `sse-swap="event_name"` for HTML fragments or `hx-trigger="sse:event_name from:body"` for fetch-on-notify (the right pattern for our JSON envelopes).
  • Notice/appeal publishers wired — these were ALREADY published when Step 9 shipped. `notice.generated` / `appeal.filed` are bound by the SSE allowlist.
  • `assignment.created` remains forward-compat — there is no canopy-assignments service yet (post-UAT).

Source

Op-infra plan Step 9 implementation (MR !154 (merged)). Scope reduced 2026-05-01 (publishers verified extant) and 2026-05-04 (htmx-sse extension closed).

Edited by Ghost User