433 lines
14 KiB
Markdown
433 lines
14 KiB
Markdown
---
|
|
id: AGD-0035
|
|
ticket: task-owned-shell-windows
|
|
title: Agenda - Task-Owned Shell Windows
|
|
status: accepted
|
|
created: 2026-05-15
|
|
resolved: 2026-05-15
|
|
decision: DEC-0027
|
|
tags: [runtime, os, task, window-manager, shell, lifecycle]
|
|
---
|
|
|
|
# Agenda - Task-Owned Shell Windows
|
|
|
|
## Contexto
|
|
|
|
O Prometeu OS ja possui `SystemOS` como autoridade semantica para coordenar
|
|
lifecycle entre `Task` e `Process`, com facades por dominio para evitar que o
|
|
firmware manipule storage interno diretamente.
|
|
|
|
O modelo atual separa:
|
|
|
|
```text
|
|
Process = execucao tecnica
|
|
Task = presenca navegavel
|
|
Window = presenca visual da task
|
|
```
|
|
|
|
O `WindowOwner` ja representa `Hub`, `Task(TaskId)` e `Overlay`. Shell apps ja
|
|
conseguem criar janelas associadas a uma task, e games continuam fora do
|
|
`WindowManager`: eles sao sessoes fullscreen conduzidas por `GameRunningStep`,
|
|
nao janelas.
|
|
|
|
Hoje, porem, `ShellRunningStep` ainda decide se continua rodando a partir de um
|
|
sinal generico: `focused_window_active`. Esse sinal vem do resultado do update
|
|
do Hub e apenas indica se existe alguma janela focada/ativa, sem confirmar que
|
|
essa janela pertence a task que o `ShellRunningStep` esta conduzindo.
|
|
|
|
## Problema
|
|
|
|
O contrato de liveness de uma Shell task ainda esta acoplado a presenca visual
|
|
generica, nao a presenca visual da propria task.
|
|
|
|
Isso deixa uma lacuna conceitual:
|
|
|
|
- uma task pode estar em `Foreground`, mas a janela focada pode pertencer a
|
|
outro owner;
|
|
- uma janela pode estar focada, mas nao representar a task que esta rodando no
|
|
`ShellRunningStep`;
|
|
- o firmware precisa inferir continuidade por um booleano generico em vez de
|
|
perguntar ao OS: "esta task ainda possui uma janela ativa/focada?".
|
|
|
|
Se `Task` e a unidade de navegacao, e `Window` e a presenca visual dessa task,
|
|
o fluxo de Shell precisa saber se a presenca visual pertence a mesma task.
|
|
|
|
## Pontos Criticos
|
|
|
|
1. Autoridade do contrato.
|
|
A pergunta deve provavelmente passar por `SystemOS` ou por uma facade de
|
|
windows/lifecycle, nao por logica espalhada no Hub. O `WindowManager` pode
|
|
armazenar e consultar janelas, mas a semantica de "task continua viva" deve
|
|
permanecer coerente com o modelo de lifecycle.
|
|
|
|
2. Foco versus atividade.
|
|
A decisao precisa separar:
|
|
- "a task possui alguma janela";
|
|
- "a task possui uma janela ativa";
|
|
- "a task possui a janela atualmente focada".
|
|
|
|
Para o `ShellRunningStep`, o criterio candidato e mais forte: a janela
|
|
focada deve pertencer a propria task.
|
|
|
|
3. Encerramento da task.
|
|
Se uma Shell task perde sua unica janela ativa/focada, o sistema precisa
|
|
decidir se isso fecha a task, suspende a task, retorna ao Hub, ou representa
|
|
erro. Para esta agenda, o foco e o contrato Task-Window; politicas futuras
|
|
de background ficam fora.
|
|
|
|
4. Separacao entre Shell e Game.
|
|
Games nao devem virar `WindowOwner::Task`. A presenca visual de game
|
|
continua sendo a propria sessao fullscreen do `GameRunningStep`. O contrato
|
|
aqui vale para Shell/system apps representados por janelas.
|
|
|
|
5. Multiplicidade futura sem resolver agora.
|
|
O contrato deve ser simples o bastante para uma janela por Shell task hoje,
|
|
mas nao deve bloquear uma evolucao posterior para multiplas janelas. A
|
|
agenda nao deve decidir dock, app switcher, services em background,
|
|
minimizacao, ou redesign da Shell.
|
|
|
|
## Opcoes
|
|
|
|
### Opcao A - Manter `focused_window_active` como criterio generico
|
|
|
|
**Abordagem:** `ShellRunningStep` continua dependendo do outcome generico do
|
|
Hub, que informa apenas se existe alguma janela focada/ativa.
|
|
|
|
**Vantagens:**
|
|
|
|
- menor mudanca imediata;
|
|
- preserva o fluxo atual de retorno ao Hub;
|
|
- evita adicionar API nova no `WindowManager` agora.
|
|
|
|
**Riscos / Custos:**
|
|
|
|
- nao expressa o modelo `Task = presenca navegavel` e `Window = presenca visual
|
|
da task`;
|
|
- permite continuidade baseada em janela de outro owner;
|
|
- mantem uma inferencia de lifecycle fora do contrato direto do OS;
|
|
- tende a piorar quando houver mais janelas ou owners.
|
|
|
|
**Leitura:** opcao aceitavel apenas como estado transitorio, nao como contrato
|
|
final.
|
|
|
|
### Opcao B - `ShellRunningStep` depende de janela focada pertencente a propria task
|
|
|
|
**Abordagem:** expor uma consulta do tipo
|
|
`focused_window_belongs_to_task(task_id)` ou
|
|
`task_has_focused_window(task_id)`. O `ShellRunningStep` continua somente se a
|
|
task estiver `Foreground` e a janela focada tiver `WindowOwner::Task(task_id)`.
|
|
|
|
**Vantagens:**
|
|
|
|
- alinha diretamente `Task` e `Window`;
|
|
- remove a ambiguidade do booleano generico;
|
|
- torna o encerramento de Shell task explicavel: sem janela focada da propria
|
|
task, nao ha presenca visual ativa para aquela task;
|
|
- funciona bem para o modelo atual de uma Shell task em foreground.
|
|
|
|
**Riscos / Custos:**
|
|
|
|
- pode ser forte demais se o futuro permitir task com janela existente mas
|
|
temporariamente sem foco;
|
|
- exige definir se perda de foco para `Hub` ou `Overlay` fecha a task ou apenas
|
|
pausa o fluxo;
|
|
- precisa tomar cuidado para overlays nao roubarem foco de forma que fechem a
|
|
task acidentalmente.
|
|
|
|
**Leitura:** e a opcao mais coerente para o contrato imediato, desde que
|
|
overlays e Hub sejam tratados explicitamente.
|
|
|
|
### Opcao C - `ShellRunningStep` depende de qualquer janela ativa pertencente a propria task
|
|
|
|
**Abordagem:** expor uma consulta do tipo `task_has_active_window(task_id)`.
|
|
Foco global continua separado: a task segue viva enquanto pelo menos uma janela
|
|
aberta/ativa pertence a ela, mesmo que outra superficie esteja focada.
|
|
|
|
**Vantagens:**
|
|
|
|
- prepara melhor um futuro com overlays, app switcher ou multiplas janelas;
|
|
- evita fechar task por perda temporaria de foco;
|
|
- separa "existencia visual da task" de "janela no topo".
|
|
|
|
**Riscos / Custos:**
|
|
|
|
- exige definir imediatamente o que significa "active" alem de `has_focus`;
|
|
- pode preservar tasks sem presenca navegavel real se a janela existir mas nao
|
|
estiver selecionada;
|
|
- abre portas para semantica de background/minimizacao, que esta fora do escopo
|
|
desta agenda.
|
|
|
|
**Leitura:** boa direcao futura, mas talvez maior que o contrato necessario
|
|
agora.
|
|
|
|
### Opcao D - Lifecycle fecha janelas; janelas nunca fecham lifecycle
|
|
|
|
**Abordagem:** `ShellRunningStep` ignora foco/janelas para continuidade; a task
|
|
so fecha quando o lifecycle manda fechar. O `WindowManager` seria apenas
|
|
reflexo visual da task, nao sinal de liveness.
|
|
|
|
**Vantagens:**
|
|
|
|
- preserva autoridade total do lifecycle;
|
|
- evita que bugs de foco encerrem task;
|
|
- simples de raciocinar em termos de `TaskState`.
|
|
|
|
**Riscos / Custos:**
|
|
|
|
- contradiz a intencao de `Window = presenca visual da task` para Shell apps;
|
|
- pode manter uma Shell task foreground sem janela visivel;
|
|
- empurra para outro mecanismo a deteccao de fechamento pelo usuario.
|
|
|
|
**Leitura:** defensavel para services/background no futuro, mas desalinhada
|
|
com Shell apps visuais neste escopo.
|
|
|
|
## Sugestao / Recomendacao
|
|
|
|
A recomendacao consolidada e seguir a Opcao B como contrato v1:
|
|
|
|
```text
|
|
ShellRunningStep continua somente quando:
|
|
1. sua Task esta em Foreground;
|
|
2. a janela focada pertence a WindowOwner::Task(task_id) da propria task.
|
|
```
|
|
|
|
Isso troca o sinal generico `focused_window_active` por uma pergunta explicita
|
|
ao `WindowFacade`:
|
|
|
|
```text
|
|
os.windows().focused_window_belongs_to_task(task_id)
|
|
```
|
|
|
|
Esse nome comunica que o `WindowManager` possui um foco global, e que a
|
|
pergunta e se esse foco global pertence a task informada. O nome
|
|
`task_has_focused_window` continua sendo conceitualmente aceitavel, mas pode
|
|
soar como se cada task tivesse um foco proprio.
|
|
|
|
O comportamento v1 recomendado e:
|
|
|
|
```text
|
|
if !ctx.os.windows().focused_window_belongs_to_task(self.task_id) {
|
|
ctx.os.lifecycle().close_task(self.task_id)?;
|
|
return Some(FirmwareState::HubHome(HubHomeStep));
|
|
}
|
|
```
|
|
|
|
O contrato deve declarar tambem:
|
|
|
|
- `Hub` e `Overlay` nao sao Shell task windows;
|
|
- games nao entram no `WindowManager`;
|
|
- a ausencia de janela focada da propria Shell task fecha ou encerra o fluxo da
|
|
Shell task conforme a politica atual, sem introduzir background service ou
|
|
minimizacao nesta decisao;
|
|
- multiplas janelas, dock, app switcher, background services e redesign da
|
|
Shell ficam fora desta agenda.
|
|
|
|
## Perguntas em Aberto
|
|
|
|
- [x] O criterio v1 deve ser "janela focada pertence a task" ou "task possui
|
|
alguma janela ativa"?
|
|
- [x] O nome da API deve falar em foco (`task_has_focused_window`) ou em
|
|
pertencimento do foco global (`focused_window_belongs_to_task`)?
|
|
- [x] Quando uma `Overlay` esta focada, ela deve preservar a Shell task
|
|
subjacente ou isso ainda nao existe no modelo atual?
|
|
- [x] Fechar a ultima janela da Shell task deve chamar `close_task(task_id)`
|
|
diretamente ou apenas retornar ao Hub e deixar lifecycle resolver?
|
|
- [x] A consulta deve morar no `WindowFacade`, em uma facade de lifecycle, ou em
|
|
uma facade composta de `SystemOS`?
|
|
- [x] A decision posterior precisa alterar somente firmware/system, ou tambem
|
|
documentar esse contrato nos specs canonicos?
|
|
|
|
## Respostas Consolidadas
|
|
|
|
### Criterio v1
|
|
|
|
O criterio v1 e "janela focada pertence a task".
|
|
|
|
`ShellRunningStep` continua somente quando:
|
|
|
|
```text
|
|
TaskState::Foreground
|
|
+
|
|
focused window owner == WindowOwner::Task(task_id)
|
|
```
|
|
|
|
A alternativa "task possui alguma janela ativa" fica reservada para um futuro
|
|
com overlays, multiplas janelas, minimizacao ou app switcher. Ela e mais ampla
|
|
do que o contrato necessario agora.
|
|
|
|
Nesta versao, Shell apps sao foreground e visualmente representados por uma
|
|
janela focada. Se a janela focada nao pertence a task, a task nao deve
|
|
continuar executando.
|
|
|
|
### Nome e local da API
|
|
|
|
O nome recomendado e:
|
|
|
|
```text
|
|
focused_window_belongs_to_task(task_id)
|
|
```
|
|
|
|
A API deve morar em `WindowFacade`:
|
|
|
|
```text
|
|
os.windows().focused_window_belongs_to_task(task_id)
|
|
```
|
|
|
|
Motivo: a pergunta e sobre foco, janela e `WindowOwner`, nao sobre transicao de
|
|
lifecycle.
|
|
|
|
A separacao de responsabilidades fica:
|
|
|
|
```text
|
|
WindowFacade
|
|
responde perguntas sobre janelas, foco e ownership
|
|
|
|
LifecycleFacade
|
|
altera TaskState e ProcessState
|
|
|
|
ShellRunningStep
|
|
coordena a decisao firmware-level entre janela e lifecycle
|
|
```
|
|
|
|
Se esse padrao se repetir, uma facade composta como `sessions()` pode surgir no
|
|
futuro, mas ela nao e necessaria para este contrato v1.
|
|
|
|
### Overlays
|
|
|
|
Overlay policy ainda nao existe no modelo atual.
|
|
|
|
Para v1:
|
|
|
|
```text
|
|
Hub nao e janela da task.
|
|
Overlay nao e janela da task.
|
|
Game nao e WindowManager window.
|
|
ShellRunningStep exige foco em WindowOwner::Task(task_id).
|
|
```
|
|
|
|
Se uma overlay puder roubar foco, isso precisa ser tratado em uma agenda
|
|
propria de overlay/modal policy. Esta decisao nao deve tentar preservar,
|
|
pausar, ou modelar Shell task sob overlay.
|
|
|
|
Possiveis direcoes futuras, fora deste escopo:
|
|
|
|
- overlay modal preserva a task subjacente;
|
|
- overlay nao-modal nao rouba foco;
|
|
- overlay possui owner/contexto proprio.
|
|
|
|
### Fechamento da Shell task
|
|
|
|
Quando a Shell task perde sua janela focada elegivel, o firmware deve chamar:
|
|
|
|
```text
|
|
os.lifecycle().close_task(task_id)
|
|
```
|
|
|
|
e entao retornar para `HubHome`.
|
|
|
|
Nao basta apenas retornar ao Hub, porque isso deixaria task/processo dependente
|
|
de cleanup implicito.
|
|
|
|
Contrato v1:
|
|
|
|
```text
|
|
Shell task perde sua janela focada elegivel
|
|
-> lifecycle.close_task(task_id)
|
|
-> TaskState::Closed
|
|
-> ProcessState::Stopped
|
|
-> FirmwareState::HubHome
|
|
```
|
|
|
|
O fechamento visual da Shell task precisa passar pelo lifecycle do `SystemOS`.
|
|
|
|
### Propagacao para specs
|
|
|
|
A decision posterior deve alterar firmware/system e tambem documentar o
|
|
contrato nos specs canonicos.
|
|
|
|
O contrato arquitetural a preservar e:
|
|
|
|
```text
|
|
Process = execucao tecnica
|
|
Task = presenca navegavel
|
|
Window = presenca visual da task
|
|
```
|
|
|
|
Tambem deve ficar documentado:
|
|
|
|
- games nao sao janelas;
|
|
- games rodam como sessoes fullscreen via `GameRunningStep`;
|
|
- Shell apps possuem janelas no `WindowManager`;
|
|
- Shell app windows usam `WindowOwner::Task(TaskId)`;
|
|
- `Hub` e `Overlay` nao sao janelas de Shell task;
|
|
- na v1, `ShellRunningStep` so continua se a janela focada pertence a sua
|
|
propria task.
|
|
|
|
Isso evita que trabalho futuro transforme game em window ou reintroduza
|
|
`focused_window_active` como contrato generico.
|
|
|
|
## Fora de Escopo
|
|
|
|
- dock;
|
|
- app switcher;
|
|
- background services;
|
|
- minimizacao;
|
|
- multiplas janelas complexas;
|
|
- redesign da Shell;
|
|
- transformar games em janelas;
|
|
- mudar o modelo fullscreen de `GameRunningStep`;
|
|
- reabrir o contrato geral de `Process`, `Task` e lifecycle ja consolidado.
|
|
|
|
## Criterio para Encerrar
|
|
|
|
Esta agenda pode virar decision quando houver resposta explicita para:
|
|
|
|
1. qual predicado `ShellRunningStep` usa para continuar;
|
|
2. onde a API de consulta Task-Window mora;
|
|
3. como `Hub`, `Overlay` e `GameRunningStep` ficam excluidos ou tratados;
|
|
4. qual comportamento ocorre quando a Shell task perde sua janela elegivel;
|
|
5. quais specs ou codigos precisam ser propagados depois da decision.
|
|
|
|
## Discussion
|
|
|
|
A discussao convergiu para um contrato v1 pequeno, focado em Shell task
|
|
foreground com janela focada propria.
|
|
|
|
Resumo da direcao:
|
|
|
|
```text
|
|
AGD-0035 segue a Opcao B.
|
|
|
|
Predicado:
|
|
focused_window_belongs_to_task(task_id)
|
|
|
|
Facade:
|
|
os.windows()
|
|
|
|
Comportamento:
|
|
se falso em ShellRunningStep:
|
|
os.lifecycle().close_task(task_id)
|
|
retorna HubHome
|
|
|
|
Fora de escopo:
|
|
overlay policy
|
|
background
|
|
minimizacao
|
|
app switcher
|
|
game windows
|
|
```
|
|
|
|
Casos de background, overlay policy, minimizacao, app switcher e multiplas
|
|
janelas devem ficar para agendas futuras.
|
|
|
|
## Resolution
|
|
|
|
Aceita em 2026-05-15 e promovida para `DEC-0027`.
|
|
|
|
A decision deve seguir a Opcao B: `ShellRunningStep` continua somente quando a
|
|
Shell task esta em `TaskState::Foreground` e a janela focada pertence a
|
|
`WindowOwner::Task(task_id)`. A API normativa e
|
|
`os.windows().focused_window_belongs_to_task(task_id)`. Quando o predicado for
|
|
falso, `ShellRunningStep` deve fechar a task via
|
|
`os.lifecycle().close_task(task_id)` e retornar `HubHome`.
|