Fix tasks server /status task lists to match heartbeat groups
Problem
/status shows summary cards whose numbers come from classify_tasks() in scripts/task_manager_lib.py (snapshot_payload → counts). The HTML body uses _classify_task_sections() in tasks/tools/tasks_server.py, which does not mirror that logic. In particular, any task with registered or dispatch_state is sent to Other before status is considered, so in-progress / dispatched work does not appear under an “Active” heading even when the Active card is non-zero. There is also no “Active tasks” list section in _render_task_sections — only Needs Attention, Ready, Blocked, Other. Operators see 13 Active in the cards but a single “Other tasks (422)” list, which feels broken.
Context
- Prior task
tasks/workstreams/infra-tooling/tasks/improve-tasks-serve-status-ui-for-operator-triage.md(completed) described “Active sections” but the shipped_render_task_sectionsnever added an Active bucket; classification diverged from the heartbeat library. - Heartbeat text summary (
render_summary) already lists Active and Needs attention in sync withclassify_tasks. - Snapshot JSON (
/status.json) is consumed by tooling; any new fields should be additive and backward-compatible. - Files:
scripts/task_manager_lib.py(snapshot_payload,classify_tasks),tasks/tools/tasks_server.py(_render_task_sections,_classify_task_sections, CSS),tests/core/test_tasks_server.py.
Possible Solutions
- Recommended: Extend
snapshot_payloadwith explicit group membership (e.g. per-taskdisplay_groupor slug lists per group) derived from the samegroupsdict used forcounts, then render/statussections from that so cards and lists cannot drift. Render Needs attention and Active tasks as<table>rows (columns: task link, status, dispatch, PR/CI, age, first attention reason) above Ready, Blocked, and Other (list or table for consistency). - Reimplement
classify_taskslogic in Python insidetasks_server.pyfrom task dicts — high drift risk, duplicate bugs. - Have tasks server shell out to heartbeat script — too heavy.
Plan
- Add structured group data to the snapshot in
snapshot_payload(minimal additive schema; document in a short comment). - Replace
_classify_task_sectionsusage with snapshot-driven grouping; add Active tasks section and keep Needs attention prominent; use tables for operator scanability. - Update/extend
test_tasks_server.pyso a fixture with mixed tasks asserts correct section headings, row counts matchingcounts, and that anin_progress+ registered task appears under Active, not only under Other. - Manual or Playwright smoke:
/statusshows separate tables when counts > 0. just task validateafter task file edits.
Implementation Progress
- 2026-03-24:
in_progress. Manager dispatch. - 2026-03-24: Added
display_groupfield to each task insnapshot_payload(scripts/task_manager_lib.py) via_build_display_group_lookup()— maps each task slug to itsclassify_tasksgroup (needs_attention wins over other groups). This is the single source of truth so cards and lists cannot drift. - 2026-03-24: Replaced
_classify_task_sectionsintasks/tools/tasks_server.py— now readsdisplay_groupfrom the snapshot instead of re-classifying. Returns a dict with 5 groups:needs_attention,active_tasks,ready_to_pick_up,waiting_on_dependencies,other. - 2026-03-24: Added "Active tasks" section to
_render_task_sections, rendered between Needs Attention and Ready to pick up. - 2026-03-24: Updated tests in
tests/core/test_tasks_server.py(new:test_classify_task_sections_uses_display_group,test_classify_task_sections_missing_display_group_falls_back,test_status_page_active_tasks_section; updated:test_classify_task_sections_completed_goes_to_other_bucket, RICH_SNAPSHOT fixture, all snapshot fixtures withdisplay_group). - 2026-03-24: Added
test_snapshot_payload_includes_display_groupintests/scripts/test_task_manager_scripts.py. - 2026-03-24:
just cipasses (85 affected tests pass; 2 pre-existing flaky timeout failures unrelated).
QA Exploration
- [x] QA exploration completed
- Launched tasks server on port 8585, navigated to
/statuswith Playwright. - With a test snapshot containing all 5 groups, verified:
- Cards show correct counts: Ready=2, Blocked=1, Active=2, Attention=1, Escalation=1.
- Sections render in order: Needs Attention (1), Active tasks (2), Ready to pick up (2), Waiting on dependencies (1), Other tasks (1).
- List counts match card numbers exactly — the core bug is fixed.
- Active tasks (registered + running dispatch) no longer appear under Other.
- PR links, CI badges, dispatch badges, blocker text all render correctly.
Review Feedback
- 2026-03-24: Review requested an explicit regression test for dual-membership tasks (
ready_to_pick_up+needs_attention) and clearer precedence around snapshot grouping. - 2026-03-24: Added
test_snapshot_payload_attention_overrides_ready_display_group; no production-code change was needed because the snapshot logic was already correct once the test forced the overdue path explicitly. - 2026-03-24: Fresh
just reviewrerun returnedAPPROVED; no blocking findings remain. - [x] Review cleared