239 lines
8.0 KiB
Markdown
239 lines
8.0 KiB
Markdown
---
|
|
id: DEC-0027
|
|
ticket: task-owned-shell-windows
|
|
title: Decision - Task-Owned Shell Windows
|
|
status: accepted
|
|
created: 2026-05-15
|
|
accepted: 2026-05-15
|
|
ref_agenda: AGD-0035
|
|
tags: [runtime, os, task, window-manager, shell, lifecycle]
|
|
---
|
|
|
|
# Decision - Task-Owned Shell Windows
|
|
|
|
## Status
|
|
|
|
Accepted on 2026-05-15. This decision is normative and ready to drive plans.
|
|
|
|
## Contexto
|
|
|
|
O Prometeu OS ja separa lifecycle tecnico e presenca navegavel:
|
|
|
|
```text
|
|
Process = execucao tecnica
|
|
Task = presenca navegavel
|
|
Window = presenca visual da task
|
|
```
|
|
|
|
`SystemOS` e a autoridade semantica para coordenar `TaskState` e
|
|
`ProcessState`. `TaskManager`, `ProcessManager` e `WindowManager` continuam
|
|
como storage/servicos de dominio, acessados por facades.
|
|
|
|
`WindowOwner` ja representa `Hub`, `Task(TaskId)` e `Overlay`. Shell apps podem
|
|
criar janelas com `WindowOwner::Task(task_id)`. Games continuam fora do
|
|
`WindowManager`: eles sao sessoes fullscreen conduzidas por `GameRunningStep`,
|
|
nao janelas.
|
|
|
|
Antes desta decision, `ShellRunningStep` dependia de um sinal generico,
|
|
`focused_window_active`, que apenas informava se existia alguma janela focada.
|
|
Esse contrato nao garantia que a janela focada pertencia a task que o
|
|
`ShellRunningStep` estava conduzindo.
|
|
|
|
## Decisao
|
|
|
|
`ShellRunningStep` MUST continuar rodando uma Shell task somente quando as duas
|
|
condicoes abaixo forem verdadeiras:
|
|
|
|
```text
|
|
TaskState::Foreground
|
|
+
|
|
focused window owner == WindowOwner::Task(task_id)
|
|
```
|
|
|
|
O predicado de janela MUST ser exposto pela `WindowFacade` como:
|
|
|
|
```text
|
|
os.windows().focused_window_belongs_to_task(task_id)
|
|
```
|
|
|
|
Esse predicado MUST consultar o foco global do `WindowManager` e responder se a
|
|
janela atualmente focada pertence a `WindowOwner::Task(task_id)`.
|
|
|
|
Quando `ShellRunningStep` detectar que a Shell task foreground nao possui a
|
|
janela focada elegivel, ele MUST fechar a task por lifecycle antes de retornar
|
|
ao Hub:
|
|
|
|
```text
|
|
Shell task perde sua janela focada elegivel
|
|
-> os.lifecycle().close_task(task_id)
|
|
-> TaskState::Closed
|
|
-> ProcessState::Stopped
|
|
-> FirmwareState::HubHome
|
|
```
|
|
|
|
O firmware MUST NOT apenas retornar ao Hub sem acionar
|
|
`os.lifecycle().close_task(task_id)`, porque isso deixaria a task/processo
|
|
dependente de cleanup implicito.
|
|
|
|
## Rationale
|
|
|
|
O modelo do OS precisa preservar a relacao direta entre task navegavel e janela
|
|
visual. Se uma Shell task esta em foreground, sua continuidade precisa depender
|
|
da janela visual da propria task, nao da existencia de qualquer janela focada.
|
|
|
|
`focused_window_belongs_to_task(task_id)` e o nome escolhido porque o foco e
|
|
global no `WindowManager`. A pergunta nao e se a task possui um subsistema de
|
|
foco proprio, mas se o foco global atual pertence aquela task.
|
|
|
|
A consulta pertence a `WindowFacade` porque ela responde sobre janela, foco e
|
|
ownership. Transicoes de estado continuam pertencendo a `LifecycleFacade`.
|
|
`ShellRunningStep` coordena os dois dominios no nivel firmware:
|
|
|
|
```text
|
|
WindowFacade
|
|
responde perguntas sobre janelas, foco e ownership
|
|
|
|
LifecycleFacade
|
|
altera TaskState e ProcessState
|
|
|
|
ShellRunningStep
|
|
coordena a decisao firmware-level entre janela e lifecycle
|
|
```
|
|
|
|
Essa separacao preserva o desenho recente de `SystemOS`: ownership e mediacao
|
|
continuam centralizados, mas cada facade responde pelo dominio certo.
|
|
|
|
## Alternativas Descartadas
|
|
|
|
### Manter `focused_window_active`
|
|
|
|
Descartado como contrato final porque o booleano generico nao codifica
|
|
ownership da task. Ele permitiria que uma Shell task continuasse por causa de
|
|
uma janela pertencente ao `Hub`, a uma `Overlay`, ou a outra task futura.
|
|
|
|
### Usar "task possui alguma janela ativa"
|
|
|
|
Descartado para v1 porque abre semantica de overlays, multiplas janelas,
|
|
minimizacao, app switcher e background. Essa direcao pode ser reavaliada em
|
|
agenda futura, mas e maior que o contrato necessario agora.
|
|
|
|
### Lifecycle fecha janelas, mas janelas nunca afetam lifecycle
|
|
|
|
Descartado para Shell apps foreground porque permitiria uma Shell task
|
|
foreground sem presenca visual propria. Isso contradiz o contrato
|
|
`Window = presenca visual da task` para apps Shell.
|
|
|
|
## Invariantes / Contrato
|
|
|
|
- `Process` MUST representar execucao tecnica.
|
|
- `Task` MUST representar presenca navegavel.
|
|
- `Window` MUST representar presenca visual de Shell/system tasks quando essas
|
|
tasks sao modeladas pelo `WindowManager`.
|
|
- Shell app windows MUST usar `WindowOwner::Task(TaskId)`.
|
|
- `Hub` MUST NOT ser tratado como janela de Shell task.
|
|
- `Overlay` MUST NOT ser tratado como janela de Shell task nesta v1.
|
|
- Games MUST NOT ser modelados como `WindowManager` windows.
|
|
- Games MUST continuar como sessoes fullscreen conduzidas por
|
|
`GameRunningStep`.
|
|
- `ShellRunningStep` MUST NOT usar `focused_window_active` como contrato de
|
|
continuidade da sua task.
|
|
- `ShellRunningStep` MUST consultar
|
|
`os.windows().focused_window_belongs_to_task(task_id)` para verificar
|
|
ownership da janela focada.
|
|
- Quando a consulta retornar falso para uma Shell task foreground,
|
|
`ShellRunningStep` MUST chamar `os.lifecycle().close_task(task_id)` e retornar
|
|
`FirmwareState::HubHome`.
|
|
- `WindowFacade` MUST responder perguntas de foco, janela e ownership.
|
|
- `LifecycleFacade` MUST executar mudancas de `TaskState` e `ProcessState`.
|
|
- Uma futura politica de overlay/modal MUST ser decidida em agenda propria se
|
|
overlays passarem a roubar foco ou preservar task subjacente.
|
|
|
|
## Impactos
|
|
|
|
### Spec
|
|
|
|
Os specs canonicos MUST documentar o contrato:
|
|
|
|
```text
|
|
Process = execucao tecnica
|
|
Task = presenca navegavel
|
|
Window = presenca visual da task
|
|
```
|
|
|
|
Eles tambem MUST documentar que games nao sao janelas, que games rodam via
|
|
`GameRunningStep`, que Shell apps usam `WindowOwner::Task(TaskId)`, e que v1 de
|
|
`ShellRunningStep` depende de foco pertencente a propria task.
|
|
|
|
### Runtime / System
|
|
|
|
`WindowFacade` precisa expor `focused_window_belongs_to_task(task_id)`.
|
|
`WindowManager` pode continuar sendo o storage de foco e janelas, mas a API
|
|
publica consumida pelo firmware deve passar pela facade.
|
|
|
|
### Firmware
|
|
|
|
`ShellRunningStep` deve substituir o uso de `focused_window_active` pela nova
|
|
consulta em `os.windows()`. Quando o predicado for falso, deve fechar a task via
|
|
`os.lifecycle().close_task(task_id)` e retornar `HubHome`.
|
|
|
|
`GameRunningStep` nao muda por esta decision.
|
|
|
|
### Host
|
|
|
|
Sem impacto direto esperado. O host nao deve precisar conhecer o contrato
|
|
Task-Window para Shell task liveness.
|
|
|
|
### Firmware / Hub
|
|
|
|
O outcome generico `focused_window_active` deixa de ser o contrato de
|
|
continuidade de `ShellRunningStep`. Ele pode permanecer como detalhe interno ou
|
|
ser removido em plano posterior, desde que nao seja usado como predicado de
|
|
liveness da Shell task.
|
|
|
|
### Tooling
|
|
|
|
Sem impacto direto esperado alem de testes.
|
|
|
|
## Propagacao Necessaria
|
|
|
|
- Criar plano de execucao a partir desta decision antes de editar specs ou
|
|
codigo.
|
|
- Atualizar specs canonicos em ingles com o contrato Task-Window.
|
|
- Adicionar `focused_window_belongs_to_task(task_id)` em `WindowFacade` e, se
|
|
fizer sentido para teste unitario, em `WindowManager`.
|
|
- Alterar `ShellRunningStep` para consultar a nova API e fechar lifecycle antes
|
|
de retornar `HubHome`.
|
|
- Ajustar ou remover o uso de `focused_window_active` no caminho de Shell
|
|
running.
|
|
- Adicionar testes para:
|
|
- janela focada da propria task permite continuidade;
|
|
- janela focada de outro owner fecha a Shell task;
|
|
- ausencia de foco fecha a Shell task;
|
|
- fechamento passa por `LifecycleFacade` e para o processo;
|
|
- games continuam fora do `WindowManager`.
|
|
|
|
## Fora de Escopo
|
|
|
|
- overlay/modal policy;
|
|
- background services;
|
|
- minimizacao;
|
|
- app switcher;
|
|
- dock;
|
|
- multiplas janelas complexas;
|
|
- redesign da Shell;
|
|
- transformar games em janelas;
|
|
- reabrir o contrato geral de `Process`, `Task` e lifecycle.
|
|
|
|
## Referencias
|
|
|
|
- Agenda: `AGD-0035`
|
|
- Discussao: `DSC-0035`
|
|
- Licao relacionada: `LSN-0040` System Pipeline Separation
|
|
- Licao relacionada: `LSN-0041` SystemOS Lifecycle Authority
|
|
- Licao relacionada: `LSN-0042` SystemOS Service Ownership Boundary
|
|
- Licao relacionada: `LSN-0043` SystemOS Domain Facades
|
|
|
|
## Revision Log
|
|
|
|
- 2026-05-15: Draft inicial criado a partir de `AGD-0035`.
|