Parent tracking issue: #141. Core phase 10 of 11; required for the first-version acceptance in #150.
Objective
Tell the local user when a remote Atenea SSH request finishes or needs attention, even when the desktop window is closed, without leaking prompt or result content.
Scope
Add a controller-owned notification outbox driven by #145 audit state and #147 reconciled remote state. The independent per-user Go controller owns delivery through native macOS, Windows and Linux adapters using the packaged app identity from #148. An OS-required registered session helper is allowed, with bounded authenticated same-user IPC and no durable history or key ownership; do not rely on a live Wails window. Prove app identity, permission and activation feasibility on each declared graphical session before implementing the complete outbox. A confirmed terminal result can produce a generic completed/failed notice. An ambiguous pending state may produce a generic attention notice without claiming the task ended. Provider completion and independently verified success remain distinct; wording must not imply semantic success from exit zero or an agent statement alone.
Default payloads contain only generic Atenea SSH text and a local opaque request ID for navigation. No hostname/alias, prompt, result, username, remote log, credentials, thread title or vault status in notification text, OS notification logs or activation URLs. The user may disable notifications; changing privacy settings is audited as metadata. Ask for OS notification permission in an appropriate user-initiated context. Denied, unavailable or headless delivery retains an unread state, visible when the authenticated app is next opened. Locked-session delivery follows the actual OS policy and uses the same generic payload; do not assume locking always suppresses notifications or report unobserved display.
Use durable event IDs derived from request UUID and state transition to coalesce repeat delivery after reconnect/restart. Record requested, OS-accepted and unknown-delivery states separately: OS acceptance does not prove the user saw it. An ambiguous crash between sending and acknowledgment cannot justify an exactly-once promise; retries follow an explicit bounded duplicate policy. Where the native service supports activation, opening a notification launches/focuses the correct local Wails app and resolves the request after normal same-user IPC authorization. Detect Linux notification action capabilities; services without actions retain the generic banner plus manual navigation to unread history. The required Linux acceptance matrix must include an action-capable session as well as this fallback. The activation payload cannot dispatch SSH, contain history plaintext or cross to another OS user/session.
Event and activation boundaries
Only locally owned request transitions create notices. Imported history (#154), backup replay and notification-delivery metadata never generate fresh task notifications. Persist outbox intent atomically with its triggering event, or deterministically reconstruct it using the same stable ID; do not lose a notice between the audit write and outbox write. Coalesce unchanged attention states, bound queue size/retries and define expiry so reconnect does not produce a stale-alert flood. Notification delivery failure never changes the remote outcome or blocks status/cancellation.
An opaque activation ID is only a lookup hint, never authorization. If history was deleted, the request is missing, or the vault is locked, show a safe unavailable/unlock state after ordinary authentication; never restore deleted payloads or execute the request. Stop-controller, logout and sleep do not promise immediate notifications; reconcile on the next eligible session and apply expiry.
Linux capability basis: the freedesktop notification protocol makes actions and activation signals optional; a delivered banner does not prove a working click action.
Acceptance criteria
Validation and evidence level
Native desktop notification tests and rendered observation on the three controller OS families, Go outbox/reconciliation fault tests and UI check/build. Record exact OS/app versions and notification permission state; source tests alone do not establish OS delivery.
Dependencies and risks
Depends on #145, #147, #148 and #151. #150 must validate this phase before core acceptance. Platform notification APIs and graphical-session packaging may differ; unsupported rows remain open rather than quietly becoming in-app-only support.
Out of scope
Remote push notifications, email/SMS alerts, display of prompts/results in lock-screen banners, and a claim that OS acceptance proves human reading.
Delivery boundary
One implementation branch/PR closes this issue only. Parent #141 remains open through #150 acceptance. No private prompts, credential material or unredacted device logs in GitHub evidence.
Parent tracking issue: #141. Core phase 10 of 11; required for the first-version acceptance in #150.
Objective
Tell the local user when a remote Atenea SSH request finishes or needs attention, even when the desktop window is closed, without leaking prompt or result content.
Scope
Add a controller-owned notification outbox driven by #145 audit state and #147 reconciled remote state. The independent per-user Go controller owns delivery through native macOS, Windows and Linux adapters using the packaged app identity from #148. An OS-required registered session helper is allowed, with bounded authenticated same-user IPC and no durable history or key ownership; do not rely on a live Wails window. Prove app identity, permission and activation feasibility on each declared graphical session before implementing the complete outbox. A confirmed terminal result can produce a generic completed/failed notice. An ambiguous pending state may produce a generic attention notice without claiming the task ended. Provider completion and independently verified success remain distinct; wording must not imply semantic success from exit zero or an agent statement alone.
Default payloads contain only generic Atenea SSH text and a local opaque request ID for navigation. No hostname/alias, prompt, result, username, remote log, credentials, thread title or vault status in notification text, OS notification logs or activation URLs. The user may disable notifications; changing privacy settings is audited as metadata. Ask for OS notification permission in an appropriate user-initiated context. Denied, unavailable or headless delivery retains an unread state, visible when the authenticated app is next opened. Locked-session delivery follows the actual OS policy and uses the same generic payload; do not assume locking always suppresses notifications or report unobserved display.
Use durable event IDs derived from request UUID and state transition to coalesce repeat delivery after reconnect/restart. Record requested, OS-accepted and unknown-delivery states separately: OS acceptance does not prove the user saw it. An ambiguous crash between sending and acknowledgment cannot justify an exactly-once promise; retries follow an explicit bounded duplicate policy. Where the native service supports activation, opening a notification launches/focuses the correct local Wails app and resolves the request after normal same-user IPC authorization. Detect Linux notification action capabilities; services without actions retain the generic banner plus manual navigation to unread history. The required Linux acceptance matrix must include an action-capable session as well as this fallback. The activation payload cannot dispatch SSH, contain history plaintext or cross to another OS user/session.
Event and activation boundaries
Only locally owned request transitions create notices. Imported history (#154), backup replay and notification-delivery metadata never generate fresh task notifications. Persist outbox intent atomically with its triggering event, or deterministically reconstruct it using the same stable ID; do not lose a notice between the audit write and outbox write. Coalesce unchanged attention states, bound queue size/retries and define expiry so reconnect does not produce a stale-alert flood. Notification delivery failure never changes the remote outcome or blocks status/cancellation.
An opaque activation ID is only a lookup hint, never authorization. If history was deleted, the request is missing, or the vault is locked, show a safe unavailable/unlock state after ordinary authentication; never restore deleted payloads or execute the request. Stop-controller, logout and sleep do not promise immediate notifications; reconcile on the next eligible session and apply expiry.
Linux capability basis: the freedesktop notification protocol makes actions and activation signals optional; a delivered banner does not prove a working click action.
Acceptance criteria
Validation and evidence level
Native desktop notification tests and rendered observation on the three controller OS families, Go outbox/reconciliation fault tests and UI check/build. Record exact OS/app versions and notification permission state; source tests alone do not establish OS delivery.
Dependencies and risks
Depends on #145, #147, #148 and #151. #150 must validate this phase before core acceptance. Platform notification APIs and graphical-session packaging may differ; unsupported rows remain open rather than quietly becoming in-app-only support.
Out of scope
Remote push notifications, email/SMS alerts, display of prompts/results in lock-screen banners, and a claim that OS acceptance proves human reading.
Delivery boundary
One implementation branch/PR closes this issue only. Parent #141 remains open through #150 acceptance. No private prompts, credential material or unredacted device logs in GitHub evidence.