diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 419f40a8..3874ab01 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,4 +1,5 @@ -{"type":"meta","next_id":{"DSC":35,"AGD":35,"DEC":27,"PLN":59,"LSN":44,"CLSN":1}} +{"type":"meta","next_id":{"DSC":36,"AGD":36,"DEC":28,"PLN":62,"LSN":44,"CLSN":1}} +{"type":"discussion","id":"DSC-0035","status":"in_progress","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[{"id":"AGD-0035","file":"AGD-0035-agenda-task-owned-shell-windows.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0027","file":"DEC-0027-decision-task-owned-shell-windows.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0035"}],"plans":[{"id":"PLN-0059","file":"PLN-0059-plan-task-window-contract-specs.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0027"]},{"id":"PLN-0060","file":"PLN-0060-plan-focused-window-ownership-api.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0027"]},{"id":"PLN-0061","file":"PLN-0061-plan-shell-running-lifecycle-integration.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0027"]}],"lessons":[]} {"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]} {"type":"discussion","id":"DSC-0020","status":"done","ticket":"jenkins-gitea-integration","title":"Jenkins Gitea Integration and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins","gitea"],"agendas":[{"id":"AGD-0018","file":"AGD-0018-jenkins-gitea-integration-and-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0003","file":"DEC-0003-jenkins-gitea-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0003","file":"PLN-0003-jenkins-gitea-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0021","file":"discussion/lessons/DSC-0020-jenkins-gitea-integration/LSN-0021-jenkins-gitea-integration.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]} diff --git a/discussion/workflow/agendas/AGD-0035-agenda-task-owned-shell-windows.md b/discussion/workflow/agendas/AGD-0035-agenda-task-owned-shell-windows.md new file mode 100644 index 00000000..cd3ee222 --- /dev/null +++ b/discussion/workflow/agendas/AGD-0035-agenda-task-owned-shell-windows.md @@ -0,0 +1,432 @@ +--- +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`. diff --git a/discussion/workflow/decisions/DEC-0027-decision-task-owned-shell-windows.md b/discussion/workflow/decisions/DEC-0027-decision-task-owned-shell-windows.md new file mode 100644 index 00000000..ae507865 --- /dev/null +++ b/discussion/workflow/decisions/DEC-0027-decision-task-owned-shell-windows.md @@ -0,0 +1,238 @@ +--- +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`. diff --git a/discussion/workflow/plans/PLN-0059-plan-task-window-contract-specs.md b/discussion/workflow/plans/PLN-0059-plan-task-window-contract-specs.md new file mode 100644 index 00000000..a81f0e05 --- /dev/null +++ b/discussion/workflow/plans/PLN-0059-plan-task-window-contract-specs.md @@ -0,0 +1,116 @@ +--- +id: PLN-0059 +ticket: task-owned-shell-windows +title: Plan - Task Window Contract Specs +status: open +created: 2026-05-15 +completed: +ref_decisions: [DEC-0027] +tags: [runtime, os, task, window-manager, shell, lifecycle, specs] +--- + +# Plan - Task Window Contract Specs + +## Briefing + +Document the task-owned shell window contract from `DEC-0027` in the canonical +runtime specs before code execution changes the observable model. + +## Decisions de Origem + +- `DEC-0027` - Task-Owned Shell Windows + +## Alvo + +The canonical specs must state that: + +- `Process` is technical execution. +- `Task` is navigable presence. +- `Window` is visual presence for shell/system tasks managed by the + `WindowManager`. +- Game cartridges are not `WindowManager` windows and continue as fullscreen + `GameRunningStep` sessions. +- Shell app windows use `WindowOwner::Task(TaskId)`. +- `Hub` and `Overlay` are not shell task windows. +- v1 `ShellRunningStep` continues only while the focused window belongs to its + own task. + +## Escopo + +Included: + +- Update [docs/specs/runtime/12-firmware-pos-and-prometeuhub.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/docs/specs/runtime/12-firmware-pos-and-prometeuhub.md) with the contract. +- Add or adjust terminology in the same file if the existing terms section is + the best local home. +- Link the contract to firmware states, AppMode behavior, and Hub/system window + responsibilities. + +## Fora de Escopo + +- Code changes in `crates/`. +- Overlay/modal policy. +- Background services, minimization, app switcher, or dock behavior. +- Multiple-window semantics beyond preserving future compatibility. +- Rewriting unrelated firmware spec sections. + +## Plano de Execucao + +1. Locate the normative spec home. + Use `docs/specs/runtime/12-firmware-pos-and-prometeuhub.md` as the primary + target because it already owns POS, Hub, AppMode, and firmware states. + +2. Extend the terms section. + Add concise definitions for `Process`, `Task`, `Window`, `WindowOwner`, and + shell task windows if they are not already present. + +3. Add a Task-Owned Shell Windows section. + State the v1 predicate explicitly: + + ```text + TaskState::Foreground + + + focused window owner == WindowOwner::Task(task_id) + ``` + + State that the runtime API is + `os.windows().focused_window_belongs_to_task(task_id)`. + +4. Clarify AppMode separation. + Under `Game`, state that games are fullscreen firmware sessions and must not + be modeled as `WindowManager` windows. Under `System`, state that shell apps + are represented through task-owned windows. + +5. Clarify lifecycle consequence. + State that when a shell task loses its eligible focused window, + `ShellRunningStep` must close the task through `SystemOS` lifecycle and then + return to Hub. + +6. Keep excluded topics explicit. + Add a short note that overlay policy, minimization, app switcher, dock, and + background services are future contracts, not part of v1. + +## Criterios de Aceite + +- [ ] The spec describes the `Process` / `Task` / `Window` model in English. +- [ ] The spec states that games are not `WindowManager` windows. +- [ ] The spec states that shell app windows use `WindowOwner::Task(TaskId)`. +- [ ] The spec states the v1 `ShellRunningStep` focused-window predicate. +- [ ] The spec states that loss of the eligible focused window closes the task + through lifecycle before returning to Hub. +- [ ] The spec does not introduce overlay, background, minimization, app + switcher, dock, or multiple-window policy. + +## Tests / Validacao + +- Run `discussion validate`. +- Review the changed spec for English-only normative text. +- Confirm every normative point from `DEC-0027` has a corresponding spec line. + +## Riscos + +- The spec may become too implementation-specific if it describes current Rust + call sites instead of the contract. +- The spec may accidentally imply overlay/modal behavior. Keep overlay + behavior explicitly out of scope. +- Future work may need a dedicated OS/window spec chapter; this plan keeps the + change local to the existing firmware/Hub spec. diff --git a/discussion/workflow/plans/PLN-0060-plan-focused-window-ownership-api.md b/discussion/workflow/plans/PLN-0060-plan-focused-window-ownership-api.md new file mode 100644 index 00000000..0d8b38d6 --- /dev/null +++ b/discussion/workflow/plans/PLN-0060-plan-focused-window-ownership-api.md @@ -0,0 +1,105 @@ +--- +id: PLN-0060 +ticket: task-owned-shell-windows +title: Plan - Focused Window Ownership API +status: open +created: 2026-05-15 +completed: +ref_decisions: [DEC-0027] +tags: [runtime, os, task, window-manager, shell, lifecycle, code] +--- + +# Plan - Focused Window Ownership API + +## Briefing + +Add the OS/window query required by `DEC-0027`: +`os.windows().focused_window_belongs_to_task(task_id)`. + +This plan owns the system-side API and tests. It does not change firmware +control flow; that is covered by `PLN-0061`. + +## Decisions de Origem + +- `DEC-0027` - Task-Owned Shell Windows + +## Alvo + +`WindowFacade` must expose a focused-window ownership predicate that answers +whether the global focused window belongs to a specific `TaskId`. + +## Escopo + +Included: + +- Add a focused ownership query to + [window.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/os/facades/window.rs). +- Add a helper in + [window_manager.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/services/windows/window_manager.rs) if it keeps the facade thin and testable. +- Add unit tests for focused-window ownership in the `prometeu-system` crate. + +## Fora de Escopo + +- Changing `ShellRunningStep`. +- Removing `focused_window_active` from `PrometeuHubOutcome`. +- Spec edits. +- Overlay/modal policy or active-window semantics. +- Multiple-window policy beyond querying the single global focused window. + +## Plano de Execucao + +1. Add `WindowManager::focused_window_belongs_to_task`. + In `crates/console/prometeu-system/src/services/windows/window_manager.rs`, + implement a method that: + - returns `false` when `focused` is `None`; + - finds the focused window by `WindowId`; + - returns `true` only when its owner is `WindowOwner::Task(task_id)`; + - returns `false` for `Hub`, `Overlay`, another task id, or stale focus. + +2. Add `WindowFacade::focused_window_belongs_to_task`. + In `crates/console/prometeu-system/src/os/facades/window.rs`, expose the + public facade method and delegate to the manager/helper. + +3. Keep existing facade methods intact. + Do not remove `focused_window()` or `windows()` in this plan. Existing call + sites may still need them until `PLN-0061` updates firmware. + +4. Add tests in `window_manager.rs`. + Cover: + - no focused window returns `false`; + - focused `WindowOwner::Task(task_id)` returns `true`; + - focused `WindowOwner::Task(other_task)` returns `false`; + - focused `WindowOwner::Hub` returns `false`; + - focused `WindowOwner::Overlay` returns `false`; + - stale focused id after window removal returns `false`. + +5. Add facade-level coverage if existing `SystemOS` tests provide a convenient + pattern. + If facade-level setup would duplicate manager coverage heavily, keep the + unit coverage at the manager level and rely on the facade as a direct + delegation. + +## Criterios de Aceite + +- [ ] `os.windows().focused_window_belongs_to_task(task_id)` compiles. +- [ ] The predicate returns `true` only for the currently focused + `WindowOwner::Task(task_id)`. +- [ ] `Hub`, `Overlay`, absent focus, stale focus, and other task owners return + `false`. +- [ ] No firmware behavior changes are included in this plan. + +## Tests / Validacao + +- Run `cargo test -p prometeu-system`. +- Run any narrower test command available for the window manager module if the + crate supports it. +- Run `discussion validate`. + +## Riscos + +- Directly scanning `windows` by focused id is simple but can hide stale focus + bugs. Tests must lock stale focus behavior to `false`. +- Adding only a facade method without manager coverage would make the contract + harder to verify. Prefer manager tests. +- Borrowing through `WindowFacade` must remain short-lived and compatible with + existing `SystemOS` facade patterns. diff --git a/discussion/workflow/plans/PLN-0061-plan-shell-running-lifecycle-integration.md b/discussion/workflow/plans/PLN-0061-plan-shell-running-lifecycle-integration.md new file mode 100644 index 00000000..91abc07a --- /dev/null +++ b/discussion/workflow/plans/PLN-0061-plan-shell-running-lifecycle-integration.md @@ -0,0 +1,128 @@ +--- +id: PLN-0061 +ticket: task-owned-shell-windows +title: Plan - Shell Running Lifecycle Integration +status: open +created: 2026-05-15 +completed: +ref_decisions: [DEC-0027] +tags: [runtime, os, task, window-manager, shell, lifecycle, firmware, tests] +--- + +# Plan - Shell Running Lifecycle Integration + +## Briefing + +Integrate the accepted task-owned window contract into `ShellRunningStep`. +`ShellRunningStep` must stop using generic focused-window presence as the +liveness contract and must close the shell task through lifecycle when the +focused window no longer belongs to that task. + +## Decisions de Origem + +- `DEC-0027` - Task-Owned Shell Windows + +## Alvo + +`ShellRunningStep` continues only when: + +```text +TaskState::Foreground ++ +os.windows().focused_window_belongs_to_task(task_id) +``` + +When that predicate is false, the step must call +`os.lifecycle().close_task(task_id)` and return `FirmwareState::HubHome`. + +## Escopo + +Included: + +- Update + [firmware_step_shell_running.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs). +- Adjust the shell-running path in + [prometeu_hub.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs) only if `focused_window_active` becomes unused or misleading. +- Add firmware/system tests proving lifecycle closure and Hub return behavior. +- Preserve `GameRunningStep` behavior. + +## Fora de Escopo + +- Spec edits; covered by `PLN-0059`. +- Adding the window ownership API; covered by `PLN-0060`. +- Overlay/modal policy. +- Background, minimization, app switcher, dock, or multiple-window behavior. +- Treating games as windows. + +## Plano de Execucao + +1. Depend on `PLN-0060`. + Do not update `ShellRunningStep` until + `os.windows().focused_window_belongs_to_task(task_id)` exists. + +2. Replace the liveness predicate in `ShellRunningStep`. + In `firmware_step_shell_running.rs`, keep the existing `TaskState` + validation. After `ctx.hub.update_shell_profile(...)`, replace the + `outcome.focused_window_active` check with: + + ```text + !ctx.os.windows().focused_window_belongs_to_task(self.task_id) + ``` + +3. Preserve crash handling order. + Keep VM crash handling before window-liveness closure so a crash reported by + the shell update remains a crash, not a normal close. + +4. Close through lifecycle before returning Hub. + When the focused-window ownership predicate is false: + - log the closure with task id; + - call `ctx.os.lifecycle().close_task(self.task_id)`; + - log lifecycle close errors; + - return `Some(FirmwareState::HubHome(HubHomeStep))`. + +5. De-emphasize or remove `focused_window_active`. + If `SystemProfileUpdate.focused_window_active` has no remaining call sites, + remove it from `SystemProfileUpdate` and its construction. If another + legitimate caller remains, keep it but do not use it for shell task + liveness. + +6. Add or update tests. + Use existing firmware tests in + [firmware.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-firmware/src/firmware/firmware.rs) + or a nearby test module. Cover: + - focused task-owned window keeps the shell path running; + - no focused window closes task and returns `HubHome`; + - focused `Hub` window closes task and returns `HubHome`; + - focused `Overlay` window closes task and returns `HubHome` in v1; + - focused window for another task closes task and returns `HubHome`; + - lifecycle close changes task to `Closed` and process to `Stopped`; + - `GameRunningStep` remains independent from `WindowManager`. + +## Criterios de Aceite + +- [ ] `ShellRunningStep` no longer uses `focused_window_active` as its + continuation contract. +- [ ] `ShellRunningStep` uses + `os.windows().focused_window_belongs_to_task(self.task_id)`. +- [ ] A false predicate closes the task through lifecycle before returning + `HubHome`. +- [ ] `Hub`, `Overlay`, absent focus, and another task's focused window all + fail the predicate for the current shell task. +- [ ] Game-running behavior is unchanged and remains outside `WindowManager`. + +## Tests / Validacao + +- Run `cargo test -p prometeu-system`. +- Run `cargo test -p prometeu-firmware`. +- Run a workspace or targeted build command used by this repository if the two + crate tests are not sufficient. +- Run `discussion validate`. + +## Riscos + +- Current Hub update behavior may close or replace windows during the same tick; + tests need to account for the final focused window after `update_shell_profile`. +- Removing `focused_window_active` may require small cleanup in system tests or + callers. +- The v1 overlay behavior is intentionally strict. Do not add overlay + preservation logic in this plan.