Move the following audited-and-implemented changes into openspec/changes/archive/2026-06-12-completed-changes-archive/: - backend-frontend-refactoring - config-profile-git-mounts - config-profile-includes-ui - config-profile-multi-repo-mounts - container-monitoring-notifications - git-mount-url-validation - home-path-expansion - mobile-terminal-ux - mount-specificity-ordering - notification-center - persistent-terminal-sessions - session-list-overhaul - ssh-key-mounting - terminal-fullscreen-unified-header - tool-session-progress-and-updates Also regenerated .pi-map*.md files for openspec/changes so the remaining active changes (multi-session-terminal-ux, reorganize-long-files, working-copies, workspace-first-ui) reflect the new layout.
7.8 KiB
PR-2 Apply Report: Backend Integration for Notification Center
Status: COMPLETE
All 5 tasks for PR-2 (NC-PR2-001 through NC-PR2-005) have been implemented, tested, and validated.
What Was Implemented
NC-PR2-001: Wire lifecycle_hooks.py to NotificationService
File: apps/api/src/services/lifecycle_hooks.py
- Imported
notification_servicesingleton fromsrc.services.notification_service - Added
_derive_title(event_type)helper mapping lifecycle events to human-readable titles:instance.created→ "Container created"instance.started→ "Container started"instance.stopped→ "Container stopped"instance.restarted→ "Container restarted"instance.deleted→ "Container deleted"instance.error→ "Container error"
- After
event_bus.publish(...), callsnotification_service.create_notification(...)with:user_id = instance.owner_idcategory = "instance"severity = "error"forinstance.error,"info"for all otherssource_type = "tool_instances",source_id = instance.id
- Wrapped in
try/except; logs failure withcorrelation_idand continues - Event bus publish and audit row insert are unaffected by notification failure
NC-PR2-002: Wire health_monitor.py to NotificationService
File: apps/api/src/services/health_monitor.py
- Imported
notification_servicesingleton - After
self._event_bus.publish(event_type, payload), callsnotification_service.create_notification(...)with:user_id = instance.owner_idcategory = "instance"fornew_status == "error"category = "health"forinstance.health_changedseveritymapped:"error"for crash"warning"for unhealthy"info"for recovery (running)
titlemapped:- "Container failed" for error
- "Container unhealthy" for unhealthy
- "Container recovered" for running
- Wrapped in
try/except; logs failure withcorrelation_idand continues - Original event bus publish and health check insert are unaffected
NC-PR2-003: Extend UserConfig schema for notification preferences
File: apps/api/src/api/user_config.py
- Added
notification_mute_categories: list[str] | None = NonetoUserConfigResponse - Added
notification_toast_level: str | None = NonetoUserConfigResponse - Added the same fields to
UserConfigUpdate - Existing config keys are unaffected; new fields are optional with
Nonedefaults
NC-PR2-004: Event producer integration tests (RED)
File: apps/api/tests/integration/test_notifications_lifecycle.py (new)
6 integration tests covering:
test_lifecycle_event_creates_notification— lifecycle hookinstance.startedcreatesseverity="info"notification for ownertest_health_monitor_error_creates_notification— simulated crash createsseverity="error"notification for ownertest_notification_failure_does_not_block_event_pipeline— mockedcreate_notificationraisingRuntimeError; event still published, no exception escapestest_notification_ownership_matches_instance_owner— notificationuser_idequalsinstance.owner_id, not the API callertest_lifecycle_error_creates_error_notification—instance.errormaps toseverity="error", title="Container error"test_health_monitor_unhealthy_creates_warning_notification— tunnel failure creatingseverity="warning", category="health"
NC-PR2-005: Verify producer tests and clean up (GREEN / REFACTOR)
- All 6 new integration tests pass
- 13 unit tests for
NotificationServicepass (no regressions) - 10 integration tests for notifications API pass (no regressions)
- 6 existing health monitor unit tests pass (no regressions)
- 6 existing event integration tests pass (no regressions)
ruff checkpasses on all modified files
TDD Cycle Evidence
| Cycle | Task | Test File | RED | GREEN | Evidence |
|---|---|---|---|---|---|
| 1 | NC-PR2-004 (producer flow) | tests/integration/test_notifications_lifecycle.py |
4 tests written against unwired producers | Wired lifecycle_hooks.py and health_monitor.py |
4 passed |
| 2 | NC-PR2-004 (severity mapping) | tests/integration/test_notifications_lifecycle.py |
Added error + warning severity tests | Already green from implementation | 6 passed |
| 3 | NC-PR2-003 (UserConfig schema) | src/api/user_config.py |
Schema extended with new optional fields | PATCH/GET endpoints validate correctly | Verified manually |
| 4 | NC-PR2-005 (REFACTOR) | All files | — | ruff clean, no regressions across 41 related tests | All pass |
Changed Files
apps/api/src/services/lifecycle_hooks.py— WiredNotificationServiceafter event bus publishapps/api/src/services/health_monitor.py— WiredNotificationServiceafter state change event publishapps/api/src/api/user_config.py— Addednotification_mute_categoriesandnotification_toast_levelto Pydantic schemasapps/api/tests/integration/test_notifications_lifecycle.py(new) — 6 integration tests for event-to-notification flow
Test Commands & Exit Codes
# New integration tests for event producers (6 tests)
cd apps/api && python -m pytest tests/integration/test_notifications_lifecycle.py -v
# Exit: 0 — 6 passed
# NotificationService unit tests (no regressions)
cd apps/api && python -m pytest tests/unit/test_notification_service.py -v
# Exit: 0 — 13 passed
# Notifications API integration tests (no regressions)
cd apps/api && python -m pytest tests/integration/test_notifications_api.py -v
# Exit: 0 — 10 passed
# Health monitor unit tests (no regressions)
cd apps/api && python -m pytest tests/unit/test_health_monitor.py -v
# Exit: 0 — 6 passed
# Event integration tests (no regressions)
cd apps/api && python -m pytest tests/integration/test_events.py -v
# Exit: 0 — 6 passed
# Combined relevant test suite
cd apps/api && python -m pytest \
tests/unit/test_notification_service.py \
tests/integration/test_notifications_api.py \
tests/integration/test_notifications_lifecycle.py \
tests/unit/test_health_monitor.py \
tests/integration/test_events.py \
-v
# Exit: 0 — 41 passed
# Ruff linting on all modified files
cd apps/api && python -m ruff check \
src/services/lifecycle_hooks.py \
src/services/health_monitor.py \
src/api/user_config.py \
tests/integration/test_notifications_lifecycle.py
# Exit: 0 — All checks passed
Deviations from Design
None. All mappings and behaviors match the design spec (section 1.3) and task requirements exactly.
Surprises / Decisions
-
Health monitor
test_health_monitor_unhealthy_creates_warning_notificationrequiredpublic_url: The health monitor only checks tunnel health wheninstance.public_urlis truthy. Without setting it on the test fixture instance,_derive_statusreturned"running"instead of"unhealthy", which created an"info"notification. Fixed by settingtest_instance.public_urlin the test before calling_check_instance. -
Patch target for failure test: The
test_notification_failure_does_not_block_event_pipelinepatchessrc.services.lifecycle_hooks.notification_service.create_notification. This only works becauselifecycle_hooks.pyimportsnotification_serviceat module level, making the attribute resolvable byunittest.mock.patch. -
No schema migration needed for UserConfig: Preferences are stored in the existing JSON
configblob, consistent with the existing pattern (theme, editor, git identity). No Alembic migration required.
Risks
- None: All changes are additive. Event producers use
try/exceptso notification failures cannot block the event pipeline. No existing test regressions introduced.
PR Boundary
This PR covers PR-2 only (NC-PR2-001 through NC-PR2-005). PR-3 (frontend core) and PR-4 (toast coordination) are out of scope.