Skip to content

feat(ssh): notify task outcomes from the local controller #155

Description

@Tutitoos

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

  • One real controller on each of macOS, Windows and Linux shows a sanitized task completion/failure notification while the Wails window is closed and the per-user controller is running.
  • Permission denial, headless or unavailable notification service leaves a truthful unread status and does not block work.
  • Duplicate/reordered terminal events, controller restart and ambiguous OS acknowledgment use stable IDs with documented delivery limits.
  • Activation reaches authenticated request detail on supported sessions; missing/deleted/locked records and action-unavailable Linux services have safe fallbacks without SSH dispatch.
  • Imported events, outbox metadata, repeated pending states, restart between audit/outbox writes and expired backlogs do not create recursive or unbounded alerts.
  • Synthetic prompt/host/credential sentinels never appear in OS notification payloads, activation links or normal logs.

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions