prometeu-runtime/discussion/workflow/agendas/AGD-0035-agenda-task-owned-shell-windows.md
2026-05-15 11:43:04 +01:00

14 KiB

id ticket title status created resolved decision tags
AGD-0035 task-owned-shell-windows Agenda - Task-Owned Shell Windows accepted 2026-05-15 2026-05-15 DEC-0027
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:

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:

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:

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:

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

  • O criterio v1 deve ser "janela focada pertence a task" ou "task possui alguma janela ativa"?
  • O nome da API deve falar em foco (task_has_focused_window) ou em pertencimento do foco global (focused_window_belongs_to_task)?
  • Quando uma Overlay esta focada, ela deve preservar a Shell task subjacente ou isso ainda nao existe no modelo atual?
  • Fechar a ultima janela da Shell task deve chamar close_task(task_id) diretamente ou apenas retornar ao Hub e deixar lifecycle resolver?
  • A consulta deve morar no WindowFacade, em uma facade de lifecycle, ou em uma facade composta de SystemOS?
  • 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:

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:

focused_window_belongs_to_task(task_id)

A API deve morar em WindowFacade:

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:

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:

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:

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:

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:

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:

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.