8.0 KiB
| id | ticket | title | status | created | accepted | ref_agenda | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DEC-0027 | task-owned-shell-windows | Decision - Task-Owned Shell Windows | accepted | 2026-05-15 | 2026-05-15 | AGD-0035 |
|
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:
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:
TaskState::Foreground
+
focused window owner == WindowOwner::Task(task_id)
O predicado de janela MUST ser exposto pela WindowFacade como:
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:
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:
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
ProcessMUST representar execucao tecnica.TaskMUST representar presenca navegavel.WindowMUST representar presenca visual de Shell/system tasks quando essas tasks sao modeladas peloWindowManager.- Shell app windows MUST usar
WindowOwner::Task(TaskId). HubMUST NOT ser tratado como janela de Shell task.OverlayMUST NOT ser tratado como janela de Shell task nesta v1.- Games MUST NOT ser modelados como
WindowManagerwindows. - Games MUST continuar como sessoes fullscreen conduzidas por
GameRunningStep. ShellRunningStepMUST NOT usarfocused_window_activecomo contrato de continuidade da sua task.ShellRunningStepMUST consultaros.windows().focused_window_belongs_to_task(task_id)para verificar ownership da janela focada.- Quando a consulta retornar falso para uma Shell task foreground,
ShellRunningStepMUST chamaros.lifecycle().close_task(task_id)e retornarFirmwareState::HubHome. WindowFacadeMUST responder perguntas de foco, janela e ownership.LifecycleFacadeMUST executar mudancas deTaskStateeProcessState.- 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:
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)emWindowFacadee, se fizer sentido para teste unitario, emWindowManager. - Alterar
ShellRunningSteppara consultar a nova API e fechar lifecycle antes de retornarHubHome. - Ajustar ou remover o uso de
focused_window_activeno 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
LifecycleFacadee 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,Taske lifecycle.
Referencias
- Agenda:
AGD-0035 - Discussao:
DSC-0035 - Licao relacionada:
LSN-0040System Pipeline Separation - Licao relacionada:
LSN-0041SystemOS Lifecycle Authority - Licao relacionada:
LSN-0042SystemOS Service Ownership Boundary - Licao relacionada:
LSN-0043SystemOS Domain Facades
Revision Log
- 2026-05-15: Draft inicial criado a partir de
AGD-0035.