prometeu-runtime/discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md
bQUARKz 82a3380426
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/head This commit looks good
Intrepid/Prometeu/Runtime/pipeline/pr-master This commit looks good
housekeeping
2026-05-15 15:51:41 +01:00

3.7 KiB

id ticket title created tags
LSN-0044 task-owned-shell-windows Task Window Liveness Belongs to the Task 2026-05-15
runtime
os
task
window-manager
shell
lifecycle

Task Window Liveness Belongs to the Task

Context

The Prometeu OS model separates execution, navigation, and visual presence:

Process = technical execution
Task = navigable presence
Window = visual presence of the task

Before DSC-0035, shell execution used a generic focused_window_active signal. That signal only answered whether any window was focused. It did not prove that the focused window represented the shell task currently driven by ShellRunningStep.

The implemented contract replaced that generic signal with a task-owned window predicate:

os.windows().focused_window_belongs_to_task(task_id)

Key Decisions

Shell liveness requires the task's own focused window

What: ShellRunningStep continues only when the task is foreground and the global focused window is owned by WindowOwner::Task(task_id).

Why: A shell task in foreground must have its own visual presence. Any focused window is not enough; the focused window must belong to the same task.

Trade-offs: This v1 rule is strict. It does not preserve a shell task under focused overlays, minimized windows, background execution, or app switcher state. Those behaviors need their own explicit contracts.

Window ownership is queried through the window facade

What: WindowFacade exposes focused_window_belongs_to_task(task_id).

Why: The question is about the global focused window and its owner. It is a window-domain query, not a lifecycle transition.

Trade-offs: Firmware still coordinates across domains: it asks the window facade for ownership and then calls lifecycle when the predicate is false.

Lifecycle still owns state transitions

What: When the shell task loses its eligible focused window, ShellRunningStep closes the task through os.lifecycle().close_task(task_id) before returning to HubHome.

Why: Returning to Hub without lifecycle closure would leave task and process state dependent on implicit cleanup.

Trade-offs: A visual close becomes a lifecycle event for foreground shell apps. That is correct for v1 shell apps, but it must not be generalized to background services without a separate decision.

Patterns and Algorithms

Use this split when OS behavior crosses services:

WindowFacade
    answers questions about windows, focus, and ownership

LifecycleFacade
    changes TaskState and ProcessState

Firmware step
    coordinates policy between the two domains

The useful pattern is not "windows close tasks". The pattern is:

  1. derive a visual-presence predicate from the window domain;
  2. let the firmware step decide what the predicate means in that state;
  3. perform lifecycle transitions through SystemOS lifecycle.

Pitfalls

  • Do not use a generic "some window is focused" signal as a task liveness contract.
  • Do not treat Hub or Overlay windows as shell task windows.
  • Do not model game cartridges as WindowManager windows. Games remain fullscreen GameRunningStep sessions.
  • Do not add overlay preservation, minimization, app switcher, or background service behavior as incidental side effects of shell liveness.
  • Do not return to Hub without closing the shell task through lifecycle.

Takeaways

  • Task-owned shell windows bind shell liveness to the task's own visual presence.
  • Ownership predicates belong in the window facade; state mutation belongs in lifecycle.
  • Strict v1 semantics are easier to evolve than an implicit "active window" concept.
  • Future overlay or background behavior should be introduced by explicit policy, not by weakening the shell liveness predicate.