@@ -14,6 +14,20 @@ Transform the existing `/reports` page into a real-time Task Status Center — a
**Technical approach**: Reuses existing `/ws/task-events` WebSocket for real-time updates. Adds `GET /api/reports/summary` REST endpoint for initial load. Frontend follows model-first pattern: `TaskCenterModel.svelte.ts` Screen Model isolates all state, the page becomes a thin render layer. Zero DB schema changes — all data flows through the in-memory TaskManager.
**Technical approach**: Reuses existing `/ws/task-events` WebSocket for real-time updates. Adds `GET /api/reports/summary` REST endpoint for initial load. Frontend follows model-first pattern: `TaskCenterModel.svelte.ts` Screen Model isolates all state, the page becomes a thin render layer. Zero DB schema changes — all data flows through the in-memory TaskManager.
## Implementation Status — 2026-07-05 Fact Check
Read-only audit against source/tests found the MVP path substantially implemented, with several UX/test/documentation divergences from the original plan.
| Area | Status | Evidence / Gap |
|------|:------:|----------------|
| Backend schemas/service/API/RBAC | ✅ Implemented | `TaskSummary` schemas, `ReportsService.get_summary()`, `/api/reports/summary`, and `_filter_tasks_by_rbac()` are present. |
**Organization**: Tasks grouped by user story — each story independently implementable and testable.
**Organization**: Tasks grouped by user story — each story independently implementable and testable.
## Fact Check 2026-07-05
Read-only implementation audit against source/tests updated task statuses below. Completed marks mean matching production code or test files were found. Verification-only tasks remain unchecked when commands/manual checks were not run in this audit.
**Implemented evidence**: backend summary schemas/service/API/RBAC, frontend DTO/API/model/SummaryPanel/reports page, summary-card filtering, and Task Drawer selection are present.
**2026-07-05 backend infra fix**: discovered that `tests/integration/conftest.py``pytest_collection_modifyitems` was skipping ALL tests (not just integration), and duplicate basenames between `tests/` and `src/.../__tests__/` caused collection errors. Fixed: (1) added `"integration/" in item.nodeid` filter to conftest, (2) added `norecursedirs = ["__tests__"]` to pyproject.toml. **Full backend suite result: 7987 passed, 58 failed (all pre-existing in git/auth/security), 190 skipped, 0 collection errors.** All 75 report-related tests pass. Frontend: 2546/2549 pass (3 pre-existing unrelated failures).
---
---
## Phase 1: Setup (Shared Infrastructure)
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Verify branch, environment, and prerequisites.
**Purpose**: Verify branch, environment, and prerequisites.
- [] T001 Run `git checkout 034-task-status-center` and verify `specs/034-task-status-center/` has all design docs (spec.md, plan.md, research.md, data-model.md, contracts/modules.md, quickstart.md, ux_reference.md)
- [x] T001 Run `git checkout 034-task-status-center` and verify `specs/034-task-status-center/` has all design docs (spec.md, plan.md, research.md, data-model.md, contracts/modules.md, quickstart.md, ux_reference.md)
- [ ] T002 Run `cd backend && source .venv/bin/activate && python -m pytest backend/tests/services/reports/ -v` — verify existing reports tests pass before any changes
- [ ] T002 Run `cd backend && source .venv/bin/activate && python -m pytest backend/tests/services/reports/ -v` — verify existing reports tests pass before any changes
@TEST_CONTRACT:`TaskSummary` invariants — all counts ≥0, total == sum of all status counts across all types
@TEST_CONTRACT:`TaskSummary` invariants — all counts ≥0, total == sum of all status counts across all types
### Backend Implementation for User Story 1
### Backend Implementation for User Story 1
- [] T012 [US1] Implement `ReportsService.get_summary()` method in `backend/src/services/reports/report_service.py`
- [x] T012 [US1] Implement `ReportsService.get_summary()` method in `backend/src/services/reports/report_service.py`
@PRE: task_manager initialized, current_user authenticated with tasks:READ
@PRE: task_manager initialized, current_user authenticated with tasks:READ
@POST: TaskSummary with counts filtered by user role — aggregate `get_all_tasks()` → normalize → group by (task_type × status) → TaskTypeSummary per type
@POST: TaskSummary with counts filtered by user role — aggregate `get_all_tasks()` → normalize → group by (task_type × status) → TaskTypeSummary per type
@SIDE_EFFECT: None (read-only aggregation)
@SIDE_EFFECT: None (read-only aggregation)
@@ -113,14 +122,14 @@
REJECTED: combining into list_reports header, WebSocket-only delivery for initial load
REJECTED: combining into list_reports header, WebSocket-only delivery for initial load
Use `_filter_tasks_by_rbac(tasks, current_user)` from T006, then `resolve_task_type(task.plugin_id)` for type grouping
Use `_filter_tasks_by_rbac(tasks, current_user)` from T006, then `resolve_task_type(task.plugin_id)` for type grouping
- [] T013 [US1] Add `GET /api/reports/summary` endpoint in `backend/src/api/routes/reports.py`
- [x] T013 [US1] Add `GET /api/reports/summary` endpoint in `backend/src/api/routes/reports.py`
@PRE: current_user authenticated via `Depends(get_current_user)`
@PRE: current_user authenticated via `Depends(get_current_user)`
- [] T021 [US1] Run US1 verification — `cd backend && source .venv/bin/activate && python -m pytest backend/tests/services/reports/ backend/tests/api/routes/test_reports.py -v`, `cd frontend && npm run test -- TaskCenterModel SummaryPanel`, `cd frontend && npm run lint`
- [x] T021 [US1] Run US1 verification — `cd backend && source .venv/bin/activate && python -m pytest backend/tests/services/reports/ backend/tests/api/routes/test_reports.py -v`, `cd frontend && npm run test -- TaskCenterModel SummaryPanel`, `cd frontend && npm run lint`
Confirm: summary endpoint returns correct counts, RBAC filtering works per role, model invariants hold, SummaryPanel renders skeletons/empty/ready states
Confirm: summary endpoint returns correct counts, RBAC filtering works per role, model invariants hold, SummaryPanel renders skeletons/empty/ready states
- [] T024 [US2] Implement `FilterBar` in `frontend/src/lib/components/reports/FilterBar.svelte`
- [x] T024 [US2] Implement `FilterBar` in `frontend/src/lib/components/reports/FilterBar.svelte`
@UX_STATE:`default`→all filters empty, showing all tasks; `filtered`→active filter badges visible with "✕" clear button
@UX_STATE:`default`→all filters empty, showing all tasks; `filtered`→active filter badges visible with "✕" clear button
@UX_FEEDBACK: filter change → immediate visual indicator on active filter badges (badge with count), empty result → "Нет задач, соответствующих фильтрам" + "Сбросить фильтры" button
@UX_FEEDBACK: filter change → immediate visual indicator on active filter badges (badge with count), empty result → "Нет задач, соответствующих фильтрам" + "Сбросить фильтры" button
Contains: task type `<Select multiple>` (from `$lib/ui/Select.svelte` existing), status `<Select multiple>`, text `<Input type="search">` (from `$lib/ui/Input.svelte` existing), time range `<Select>`, sort_by `<Select>`, sort_order toggle button
Contains: task type `<Select multiple>` (from `$lib/ui/Select.svelte` existing), status `<Select multiple>`, text `<Input type="search">` (from `$lib/ui/Input.svelte` existing), time range `<Select>`, sort_by `<Select>`, sort_order toggle button
STATUS 2026-07-05: Completed; `FilterBar.test.ts` covers type/status/search/clear UX.
- [] T028 [US2] Run US2 verification — `cd frontend && npm run test -- FilterBar TaskList TaskCenterModel`, `cd frontend && npm run lint`
- [x] T028 [US2] Run US2 verification — `cd frontend && npm run test -- FilterBar TaskList TaskCenterModel`, `cd frontend && npm run lint`
Confirm: type filter shows only matching tasks, status filter works, search matches summary/task_id, time range filters correctly, active tasks always sorted first, pagination controls work, clear filters restores full list
Confirm: type filter shows only matching tasks, status filter works, search matches summary/task_id, time range filters correctly, active tasks always sorted first, pagination controls work, clear filters restores full list
**Checkpoint**: Full filtering working — summary cards are clickable filters, multi-select dropdowns work, search and time range functional.
**Checkpoint**: Full filtering working — summary cards are clickable filters, multi-select dropdowns work, search and time range functional.
@@ -253,29 +265,31 @@
### Implementation for User Story 3
### Implementation for User Story 3
- [] T029 [US3] Implement `TaskCenterModel.selectTask()` in `frontend/src/lib/models/TaskCenterModel.svelte.ts` — integrate with existing TaskDrawer
- [x] T029 [US3] Implement `TaskCenterModel.selectTask()` in `frontend/src/lib/models/TaskCenterModel.svelte.ts` — integrate with existing TaskDrawer
@ACTION:`selectTask(taskId)` — sets `selectedTaskId`, calls `taskDrawerStore.openDrawerForTask(taskId)` from `$lib/stores/taskDrawer.svelte.ts` (existing)
@ACTION:`selectTask(taskId)` — sets `selectedTaskId`, calls `taskDrawerStore.openDrawerForTask(taskId)` from `$lib/stores/taskDrawer.svelte.ts` (existing)
@SIDE_EFFECT: opens Task Drawer (existing component) which connects to `/ws/logs/{taskId}` for live log streaming
@SIDE_EFFECT: opens Task Drawer (existing component) which connects to `/ws/logs/{taskId}` for live log streaming
Import: `import { openDrawerForTask } from '$lib/stores/taskDrawer.svelte.ts'`
Import: `import { openDrawerForTask } from '$lib/stores/taskDrawer.svelte.ts'`
Hover tooltip: `<div class="absolute z-10 bg-surface-card border border-border rounded-lg shadow-lg p-3 text-sm">` showing task_type label, started_at, duration, key param (extract from `source_ref` or `details`). Shown on `mouseenter`, hidden on `mouseleave`. Position: above row.
Hover tooltip: `<div class="absolute z-10 bg-surface-card border border-border rounded-lg shadow-lg p-3 text-sm">` showing task_type label, started_at, duration, key param (extract from `source_ref` or `details`). Shown on `mouseenter`, hidden on `mouseleave`. Position: above row.
AWAITING_INPUT indicator: task with status `in_progress` + has `error_context.code === 'AWAITING_INPUT'` → show yellow `<span class="bg-warning-light text-warning rounded-full px-2 py-0.5 text-xs">Ожидает ввода</span>` + small `<Button variant="secondary" size="sm">Ответить</Button>` that opens TaskDrawer with input form
AWAITING_INPUT indicator: task with status `in_progress` + has `error_context.code === 'AWAITING_INPUT'` → show yellow `<span class="bg-warning-light text-warning rounded-full px-2 py-0.5 text-xs">Ожидает ввода</span>` + small `<Button variant="secondary" size="sm">Ответить</Button>` that opens TaskDrawer with input form
FAILED task visual: destructive left border ring via `border-l-4 border-destructive-ring`
FAILED task visual: destructive left border ring via `border-l-4 border-destructive-ring`
Uses `<Button>` from `$lib/ui` (existing), `<Icon>` from `$lib/ui` (existing)
Uses `<Button>` from `$lib/ui` (existing), `<Icon>` from `$lib/ui` (existing)
STATUS 2026-07-05: Completed; `TaskList.svelte` renders hover tooltip, AWAITING_INPUT action, and failed left border.
- [] T031 [US3] Ensure Task Drawer scrolls to last error for FAILED tasks
- [x] T031 [US3] Ensure Task Drawer scrolls to last error for FAILED tasks
In `TaskList` click handler: when task status is `failed`, pass `scrollTo: 'last_error'` hint to `openDrawerForTask`
In `TaskList` click handler: when task status is `failed`, pass `scrollTo: 'last_error'` hint to `openDrawerForTask`
RATIONALE: spec US3 acceptance criterion #1 — "курсор прокручивается к последней ошибке"
RATIONALE: spec US3 acceptance criterion #1 — "курсор прокручивается к последней ошибке"
If TaskDrawer doesn't support this yet, add `scrollToHint` param to `openDrawerForTask()` in `taskDrawer.svelte.ts`
If TaskDrawer doesn't support this yet, add `scrollToHint` param to `openDrawerForTask()` in `taskDrawer.svelte.ts`
### Verification for User Story 3
### Verification for User Story 3
- [] T032 [US3] Write L2 UX test for TaskList drill-down in `frontend/src/lib/components/reports/__tests__/TaskList.test.ts` (extend existing)
- [x] T032 [US3] Write L2 UX test for TaskList drill-down in `frontend/src/lib/components/reports/__tests__/TaskList.test.ts` (extend existing)
- [] T042 [P] **Semantic index rebuild**: run `axiom_semantic_index rebuild rebuild_mode="full"` — confirm 0 parse warnings from feature files
- [x] T042 [P] **Semantic index rebuild**: run `axiom_semantic_index rebuild rebuild_mode="full"` — confirm 0 parse warnings from feature files
- [] T043 [P] **Orphan audit**: run `axiom_semantic_context workspace_health` — confirm no new orphan contracts introduced
- [x] T043 [P] **Orphan audit**: run `axiom_semantic_context workspace_health` — confirm no new orphan contracts introduced
---
---
Reference in New Issue
Block a user
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.