UAT: A2A facade event.subscribe registers a no-op callback — subscribers never receive published events #3172

Open
opened 2026-04-05 07:16:42 +00:00 by freemo · 2 comments
Owner

Metadata

  • Branch: fix/a2a-event-subscribe-polling
  • Commit Message: fix(a2a): expose event polling endpoint for event.subscribe subscribers
  • Milestone: v3.5.0 (M6: Autonomy Hardening)
  • Parent Epic: #933

Bug Report

Feature Area: A2A Facade — Event Queue Publish/Subscribe (M6: Autonomy Hardening)

What was tested

The A2A local facade handler for event.subscribe operation and the event queue publish/subscribe mechanism.

Expected behavior (from spec)

Per docs/specification.md §Event Streaming and the A2A protocol, event.subscribe should register a callback that receives events published to the queue. Subscribers should be notified when plan lifecycle events (PLAN_CREATED, PLAN_PHASE_CHANGED, etc.) are published.

Actual behavior (from code analysis)

In src/cleveragents/a2a/facade.py, _handle_event_subscribe registers a no-op callback that discards all events:

# Lines 483-492
def _handle_event_subscribe(self, params: dict[str, Any]) -> dict[str, Any]:
    queue = self._event_queue
    if queue is None:
        return {"subscription_id": str(ULID()), "status": "subscribed"}

    def _noop_callback(_event: Any) -> None:
        """Default no-op callback for subscriptions."""

    sub_id = queue.subscribe_local(_noop_callback)
    return {"subscription_id": sub_id, "status": "subscribed"}

The _noop_callback function does nothing — it discards every event it receives. This means:

  1. A caller receives a subscription_id and "status": "subscribed" — indicating success
  2. But the subscription never delivers any events to the caller
  3. There is no mechanism for the caller to provide their own callback through the A2A protocol

The A2aEventQueue itself is correctly implemented with publish(), subscribe_local(), and get_events() methods. The issue is that the facade's event.subscribe handler doesn't expose a way for callers to receive events.

Code location

  • src/cleveragents/a2a/facade.py, lines 483-492 (_handle_event_subscribe)
  • src/cleveragents/a2a/events.py, lines 60-88 (working A2aEventQueue)

Steps to reproduce

  1. Wire an A2aEventQueue into A2aLocalFacade
  2. Dispatch event.subscribe — receive a subscription_id
  3. Publish an event to the queue
  4. Observe that the subscriber's callback is never invoked (it's a no-op)

Impact

  • The event queue publish/subscribe mechanism is broken at the A2A facade level
  • Plan lifecycle events (PLAN_CREATED, PLAN_PHASE_CHANGED, etc.) are published to the queue but never delivered to A2A subscribers
  • This is a core M6 Autonomy Hardening feature — event-driven monitoring of plan execution is non-functional

Proposed Fix

The event.subscribe handler should either:

  1. Return a polling endpoint (e.g., get_events URL) that callers can use to retrieve queued events
  2. Or use SSE (Server-Sent Events) via SseEventFormatter for streaming delivery

The A2aEventQueue.get_events() method provides a polling mechanism that could be exposed via a separate event.poll operation.

Subtasks

  • Add event.poll operation to retrieve queued events by subscription_id
  • Or implement SSE streaming for event delivery
  • Remove the no-op callback from _handle_event_subscribe
  • Add BDD tests for event publish/subscribe round-trip
  • Verify events published via EventBusBridge are retrievable by subscribers

Definition of Done

  • A subscriber can receive events published after subscribing
  • BDD tests verify the publish/subscribe round-trip
  • The no-op callback is replaced with a functional delivery mechanism
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/a2a-event-subscribe-polling` - **Commit Message**: `fix(a2a): expose event polling endpoint for event.subscribe subscribers` - **Milestone**: v3.5.0 (M6: Autonomy Hardening) - **Parent Epic**: #933 ## Bug Report **Feature Area**: A2A Facade — Event Queue Publish/Subscribe (M6: Autonomy Hardening) ### What was tested The A2A local facade handler for `event.subscribe` operation and the event queue publish/subscribe mechanism. ### Expected behavior (from spec) Per `docs/specification.md` §Event Streaming and the A2A protocol, `event.subscribe` should register a callback that receives events published to the queue. Subscribers should be notified when plan lifecycle events (PLAN_CREATED, PLAN_PHASE_CHANGED, etc.) are published. ### Actual behavior (from code analysis) In `src/cleveragents/a2a/facade.py`, `_handle_event_subscribe` registers a **no-op callback** that discards all events: ```python # Lines 483-492 def _handle_event_subscribe(self, params: dict[str, Any]) -> dict[str, Any]: queue = self._event_queue if queue is None: return {"subscription_id": str(ULID()), "status": "subscribed"} def _noop_callback(_event: Any) -> None: """Default no-op callback for subscriptions.""" sub_id = queue.subscribe_local(_noop_callback) return {"subscription_id": sub_id, "status": "subscribed"} ``` The `_noop_callback` function does nothing — it discards every event it receives. This means: 1. A caller receives a `subscription_id` and `"status": "subscribed"` — indicating success 2. But the subscription never delivers any events to the caller 3. There is no mechanism for the caller to provide their own callback through the A2A protocol The `A2aEventQueue` itself is correctly implemented with `publish()`, `subscribe_local()`, and `get_events()` methods. The issue is that the facade's `event.subscribe` handler doesn't expose a way for callers to receive events. ### Code location - `src/cleveragents/a2a/facade.py`, lines 483-492 (`_handle_event_subscribe`) - `src/cleveragents/a2a/events.py`, lines 60-88 (working `A2aEventQueue`) ### Steps to reproduce 1. Wire an `A2aEventQueue` into `A2aLocalFacade` 2. Dispatch `event.subscribe` — receive a `subscription_id` 3. Publish an event to the queue 4. Observe that the subscriber's callback is never invoked (it's a no-op) ### Impact - The event queue publish/subscribe mechanism is broken at the A2A facade level - Plan lifecycle events (PLAN_CREATED, PLAN_PHASE_CHANGED, etc.) are published to the queue but never delivered to A2A subscribers - This is a core M6 Autonomy Hardening feature — event-driven monitoring of plan execution is non-functional ### Proposed Fix The `event.subscribe` handler should either: 1. Return a polling endpoint (e.g., `get_events` URL) that callers can use to retrieve queued events 2. Or use SSE (Server-Sent Events) via `SseEventFormatter` for streaming delivery The `A2aEventQueue.get_events()` method provides a polling mechanism that could be exposed via a separate `event.poll` operation. ## Subtasks - [ ] Add `event.poll` operation to retrieve queued events by subscription_id - [ ] Or implement SSE streaming for event delivery - [ ] Remove the no-op callback from `_handle_event_subscribe` - [ ] Add BDD tests for event publish/subscribe round-trip - [ ] Verify events published via `EventBusBridge` are retrievable by subscribers ## Definition of Done - [ ] A subscriber can receive events published after subscribing - [ ] BDD tests verify the publish/subscribe round-trip - [ ] The no-op callback is replaced with a functional delivery mechanism - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.5.0 milestone 2026-04-05 07:18:01 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Critical/High — event.subscribe returning no-op callbacks means the entire event system is non-functional for A2A clients
  • Milestone: v3.5.0 (M6: Autonomy Hardening)
  • MoSCoW: Must Have — the v3.5.0 acceptance criteria require "Event queue publish/subscribe operational"; a no-op subscriber callback directly violates this
  • Parent Epic: #397 (Server & Autonomy Infrastructure)

This is a blocking bug for the event-driven architecture. Without functional event subscriptions, agents cannot react to plan lifecycle events.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: Critical/High — event.subscribe returning no-op callbacks means the entire event system is non-functional for A2A clients - **Milestone**: v3.5.0 (M6: Autonomy Hardening) - **MoSCoW**: Must Have — the v3.5.0 acceptance criteria require "Event queue publish/subscribe operational"; a no-op subscriber callback directly violates this - **Parent Epic**: #397 (Server & Autonomy Infrastructure) This is a blocking bug for the event-driven architecture. Without functional event subscriptions, agents cannot react to plan lifecycle events. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Author
Owner

Label compliance fix applied:

  • Removed conflicting label: Priority/High
  • Kept: Priority/Critical
  • Reason: Issue had two conflicting Priority/* labels. Per CONTRIBUTING.md, exactly one Priority/* label is required. Priority/Critical takes precedence as the higher severity.

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: ca-backlog-groomer

Label compliance fix applied: - Removed conflicting label: `Priority/High` - Kept: `Priority/Critical` - Reason: Issue had two conflicting `Priority/*` labels. Per CONTRIBUTING.md, exactly one `Priority/*` label is required. `Priority/Critical` takes precedence as the higher severity. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#3172
No description provided.