Maestro task: 4d7bae00-c930-4124-8d8e-36db7a96a0a7 — "SSE endpoint and the quest-completed transition"
Done-condition: The API exposes an SSE endpoint (GET /api/v1/panel/events) that streams transitions, backed by ONE in-process publisher (api/events.py) that route handlers call. Completing an instance through the panel complete route publishes a quest-completed transition carrying the documented payload fields (child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at, was_on_time). A test subscribes to the SSE stream, completes an instance, and asserts the emitted event type and its payload fields.
Changes:
api/events.py (NEW): single in-process TransitionPublisher (per-app, app.state.publisher, installed in the lifespan); bounded per-subscriber asyncio queues, non-blocking publish with drop-on-full, clean teardown on disconnect.
api/routes_panel.py: GET /api/v1/panel/events returns text/event-stream and frames each event as event: <type>\ndata: <json>\n\n; the complete route publishes exactly once, only on result.appended, with the payload built by nestquest_core.events.build_quest_completed_event (never hand-built).
api/nestquest_core.py: exposes the core events module (core_events) following the existing importlib pattern.
tests/test_api_sse.py (NEW): streams from a real uvicorn app on an ephemeral port (httpx's ASGITransport buffers endless SSE bodies), asserts the completed event type and all documented payload fields, and that a no-op re-complete publishes nothing; all reads timeout-bounded.
Tests (TZ=UTC):
TZ=UTC uv run pytest -q → 1608 passed in 7.53s (baseline 1605 + 3 new)
TZ=UTC uv run pytest -q tests/test_api_sse.py → 3 passed in 1.10s
Maestro task: 4d7bae00-c930-4124-8d8e-36db7a96a0a7 — "SSE endpoint and the quest-completed transition"
Done-condition: The API exposes an SSE endpoint (GET /api/v1/panel/events) that streams transitions, backed by ONE in-process publisher (api/events.py) that route handlers call. Completing an instance through the panel complete route publishes a quest-completed transition carrying the documented payload fields (child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at, was_on_time). A test subscribes to the SSE stream, completes an instance, and asserts the emitted event type and its payload fields.
Changes:
- api/events.py (NEW): single in-process TransitionPublisher (per-app, app.state.publisher, installed in the lifespan); bounded per-subscriber asyncio queues, non-blocking publish with drop-on-full, clean teardown on disconnect.
- api/routes_panel.py: GET /api/v1/panel/events returns text/event-stream and frames each event as `event: <type>\ndata: <json>\n\n`; the complete route publishes exactly once, only on result.appended, with the payload built by nestquest_core.events.build_quest_completed_event (never hand-built).
- api/nestquest_core.py: exposes the core events module (core_events) following the existing importlib pattern.
- tests/test_api_sse.py (NEW): streams from a real uvicorn app on an ephemeral port (httpx's ASGITransport buffers endless SSE bodies), asserts the completed event type and all documented payload fields, and that a no-op re-complete publishes nothing; all reads timeout-bounded.
Tests (TZ=UTC):
- TZ=UTC uv run pytest -q → 1608 passed in 7.53s (baseline 1605 + 3 new)
- TZ=UTC uv run pytest -q tests/test_api_sse.py → 3 passed in 1.10s
The panel needs live transitions, so add ONE in-process publisher
(api/events.py, installed on app.state.publisher in the lifespan) and
a GET /api/v1/panel/events SSE route on the panel router — it inherits
the single require_panel_token check. The complete route now builds
the event through the core builder and publishes it only when the
core's .appended flag says an actual transition happened; a no-op
re-complete publishes nothing. Tests stream from a real uvicorn
instance on an ephemeral port because httpx's ASGITransport buffers
endless SSE bodies.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Maestro task: 4d7bae00-c930-4124-8d8e-36db7a96a0a7 — "SSE endpoint and the quest-completed transition"
Done-condition: The API exposes an SSE endpoint (GET /api/v1/panel/events) that streams transitions, backed by ONE in-process publisher (api/events.py) that route handlers call. Completing an instance through the panel complete route publishes a quest-completed transition carrying the documented payload fields (child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at, was_on_time). A test subscribes to the SSE stream, completes an instance, and asserts the emitted event type and its payload fields.
Changes:
event: <type>\ndata: <json>\n\n; the complete route publishes exactly once, only on result.appended, with the payload built by nestquest_core.events.build_quest_completed_event (never hand-built).Tests (TZ=UTC):
Independent Claude Sonnet 5 review completed for this exact commit.