3.7 KiB
| id | ticket | title | created | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| LSN-0044 | task-owned-shell-windows | Task Window Liveness Belongs to the Task | 2026-05-15 |
|
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:
- derive a visual-presence predicate from the window domain;
- let the firmware step decide what the predicate means in that state;
- perform lifecycle transitions through
SystemOSlifecycle.
Pitfalls
- Do not use a generic "some window is focused" signal as a task liveness contract.
- Do not treat
HuborOverlaywindows as shell task windows. - Do not model game cartridges as
WindowManagerwindows. Games remain fullscreenGameRunningStepsessions. - 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.