Message Flow — settling window + status visuals + energy particles¶
Motivation¶
A BLAST job appeared on the dashboard Message Flow card when it started and
then vanished mid-run, and a finished/failed job was dropped the instant it
left the active set — there was no "running" persistence, no error state, and no
sense of live activity. Root cause: the card's active set was only
{queued, running}, so a job entering the canonical reducing (result-merge)
phase — or the freshly-submitted pending state — silently disappeared, and
terminal jobs were removed immediately.
User-facing change¶
- Running jobs stay visible for their whole lifecycle. The active set now
matches the canonical in-flight set
{queued, pending, running, reducing}used everywhere else (JobStateRepository.list_active, auto-stop). Areducingjob no longer vanishes. - Finished/failed jobs linger and fade out instead of being yanked. A
recently-terminal job (
completed/failed/cancelled) stays as asettlingbox for a short window (default 90s,MESSAGE_FLOW_SETTLING_SECONDS) so the operator can see it finished or failed before it fades. These are real jobstate rows, never fabricated, and do not inflate the active counts. - Status-aware visuals. Failed jobs read in a danger tone with a broken-cross marker (colour is never the only signal); reducing pulses slower as "merging"; queued/pending stay dashed; completed/cancelled use a calm done/neutral tone.
- Moving energy particles. Glowing dots travel producer → job → cluster along
active links (running/reducing carry two faster particles, queued one slow
drift), so a live run reads as energy in motion. Running links stay bright
regardless of age (the old age-only fade made a long run look vanished).
Everything honours
prefers-reduced-motion(no particles, static halos). - Card stays populated while anything is active OR settling, collapsing to the calm "no active messages" line only when truly idle. It also polls faster (8s) while work is in flight and backs off (20s) when idle.
- New legend entries (reducing, failed, finishing/fading, moving dots = live energy); the job detail surfaces an error code when present.
API / IaC diff summary¶
GET /api/monitor/message-flowsnapshot additions (all optional, backward compatible):settling_total; per-broker-boxupdated_at,lifecycle(active/settling),error_code; per-clustersettling.- New env var
MESSAGE_FLOW_SETTLING_SECONDS(default 90, bounded 1–3600). - No IaC change.
Validation evidence¶
- Backend:
uv run pytest -q api/tests/test_message_flow.py→ 13 passed (added: pending/reducing active, settling-without-inflating-counts, old terminal excluded, env-override).test_route_contracts.pygreen. - Frontend:
npx vitest run src/components/cards/MessageFlow→ 30 passed (added colorsstatusTone/isErrorStatus/jobTone+ tooltip settling/error cases).npm run buildclean;eslintclean. uv run ruff checkclean on the changed Python files.