feat(task-manager): track published pub/sub topics and expose via API (#329)

Description

There was no easy way to see which events are published over pub/sub in a Juice instance — information needed, for example, to configure the parameter monitor. This MR makes the task manager track every unique pub/sub topic it sees, with a last-seen timestamp, and exposes that list through a task and a client helper.

Topics are observed at the single choke point all events pass through — the task manager's ZMQProxy — rather than instrumenting each publisher (which would miss other services) or running a duplicate subscriber socket (redundant with the proxy).

Closes #329 (closed)

Changes

Core

  • ZMQProxy gains an optional, failure-safe on_message(topic_frame) hook; the proxy stays generic with no task-manager coupling.
  • New TopicRegistry: in-memory dict[str, str] that decodes/dedupes topics and records a UTC ISO-8601 last-seen timestamp. Retained for the task-manager process lifetime.
  • New GetEventTopicList task; registered on the task manager to return the snapshot.

Client API

  • New get_active_topics() helper — from orangeqs.juice.client import get_active_topics (deferred imports avoid a client:left_right_arrow:task_manager cycle).

Usage

client.execute("task-manager", GetEventTopicList())
# or, the higher-level helper:
from orangeqs.juice.client import get_active_topics
get_active_topics()
# {"TaskEvent": "2026-06-05T10:30:00+00:00",
#  "IPythonServiceState.my-service": "2026-06-05T10:31:12+00:00"}

Acceptance criteria

  • Tracks all unique pub/sub topics (captured at the proxy)
  • Last-seen timestamp per topic
  • Deduplicated (dict keys)
  • Retained for the task-manager process lifetime (in-memory)
  • GetEventTopicList callable via client.execute(...)
  • Bonus: get_active_topics() high-level helper

Testing

  • New unit tests: TopicRegistry (dedup/strip/snapshot-copy) and the proxy on_message callback.
  • ruff check + ruff format clean; pyright introduces zero new errors over the baseline.
  • pytest tests/juice/task_manager tests/juice/messaging → 41 passed, 1 pre-existing skip.

Notes

The actual routing target is "task-manager" (hyphen) — the issue's "task_manager" is informal; get_active_topics() uses the correct name.

Merge request reports

Loading