diff --git a/.gitignore b/.gitignore index b8a7613d..00b87bf0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # ===== Rust / Cargo ===== +.cargo/config.toml /target/ **/target/ diff --git a/discussion/index.ndjson b/discussion/index.ndjson index f2e2d13d..fbd229b4 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,4 +1,5 @@ -{"type":"meta","next_id":{"DSC":34,"AGD":34,"DEC":26,"PLN":58,"LSN":41,"CLSN":1}} +{"type":"meta","next_id":{"DSC":35,"AGD":35,"DEC":27,"PLN":59,"LSN":41,"CLSN":1}} +{"type":"discussion","id":"DSC-0034","status":"in_progress","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":[{"id":"AGD-0034","file":"AGD-0034-agenda-systemos-domain-facades.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0026","file":"DEC-0026-systemos-domain-facades.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0034"}],"plans":[{"id":"PLN-0058","file":"PLN-0058-systemos-domain-facades-first-wave.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0026"]}],"lessons":[]} {"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"}]} {"type":"discussion","id":"DSC-0021","status":"done","ticket":"asset-entry-codec-enum-with-metadata","title":"Asset Entry Codec Enum Contract","created_at":"2026-04-09","updated_at":"2026-04-09","tags":["asset","runtime","codec","metadata"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"discussion/lessons/DSC-0021-asset-entry-codec-enum-contract/LSN-0024-string-on-the-wire-enum-in-runtime.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]} diff --git a/discussion/workflow/agendas/AGD-0034-agenda-systemos-domain-facades.md b/discussion/workflow/agendas/AGD-0034-agenda-systemos-domain-facades.md new file mode 100644 index 00000000..2e0e240a --- /dev/null +++ b/discussion/workflow/agendas/AGD-0034-agenda-systemos-domain-facades.md @@ -0,0 +1,353 @@ +--- +id: AGD-0034 +ticket: system-os-domain-facades +title: Agenda - SystemOS Domain Facades +status: accepted +created: 2026-05-15 +resolved: 2026-05-15 +decision: DEC-0026 +tags: [runtime, os, services, api-surface, lifecycle, fs] +--- + +# Agenda - SystemOS Domain Facades + +## Contexto + +Depois de `DEC-0024` e `DEC-0025`, `SystemOS` passou a concentrar ownership e +coordenação de vários domínios do Prometeu OS: + +```text +SystemOS + vm_runtime + process_manager + task_manager + window_manager + log_service + fs / fs_state / open_files / next_handle + memcard + lifecycle methods + VM initialize/tick helpers +``` + +Essa concentração é correta do ponto de vista de ownership: o OS deve ser dono +ou mediador dos serviços do console. O problema agora é a superfície pública do +root. Se tudo fica como `os.bla()`, `os.campo.bla()` ou campos públicos soltos, +o `SystemOS` vira um objeto largo demais e deixa de comunicar domínio. + +A intenção proposta é separar a superfície em compartimentos: + +```text +os.lifecycle().suspend_task(...) +os.lifecycle().resume_task(...) +os.lifecycle().crash_task(...) + +os.sessions().create_vm_game_task(...) +os.sessions().create_vm_shell_task(...) +os.sessions().create_native_shell_task(...) + +os.vm().initialize(...) +os.vm().tick(...) + +os.fs().mount(...) +os.fs().open(...) +os.fs().read(...) +os.fs().write(...) +os.fs().close(...) + +os.window().add_window(...) +os.window().set_focus(...) +os.window().focused_window(...) +os.window().close_window(...) +``` + +Logging pode continuar na raiz como operação transversal: + +```text +os.log(...) +``` + +## Problema + +O `SystemOS` está crescendo wild na raiz. Isso cria alguns riscos: + +- novos domínios tendem a adicionar mais métodos diretamente em `SystemOS`; +- lifecycle, filesystem, window, VM runtime e memcard competem pela mesma + superfície; +- testes e firmware continuam alcançando managers internos diretamente; +- fica difícil distinguir API semântica de OS de detalhe interno de serviço; +- a raiz pública pode virar uma coleção de campos públicos em vez de uma + interface de sistema. + +O ponto importante: não queremos desfazer o ownership do `SystemOS`. Queremos +compartimentalizar o acesso. + +## Pontos Criticos + +- `SystemOS` deve continuar sendo o boundary de ownership e coordenação. +- Facades não devem virar owners independentes que duplicam estado. +- A raiz do OS deve ficar pequena e expressiva. +- Lifecycle deve continuar coordenando `TaskState` e `ProcessState` junto. +- Filesystem tem estado composto (`VirtualFS`, `FsState`, `open_files`, + `next_handle`) e por isso se beneficia de uma facade própria. +- Window management já é serviço do OS, mas `PrometeuHub` e firmware ainda + acessam `os.window_manager` diretamente. +- VM runtime talvez também precise de facade ou área própria, mas isso pode ser + uma etapa posterior para não misturar com lifecycle/fs. +- O formato da facade precisa respeitar borrow rules em Rust; campos públicos + simples podem não ser viáveis quando uma operação precisa de múltiplos campos + internos do `SystemOS`. + +## Opcoes + +### Opcao A - Manter tudo na raiz do SystemOS + +**Abordagem:** +Continuar adicionando métodos e campos diretamente em `SystemOS`. + +**Vantagens:** +- menor mudança imediata; +- callsites simples; +- menos tipos auxiliares; +- evita atrito com borrow checker. + +**Custos / Riscos:** +- a raiz continua crescendo; +- domínios ficam misturados; +- incentiva acesso direto a managers internos; +- torna mais difícil explicar a API do OS; +- cada nova capability aumenta a pressão no mesmo arquivo e no mesmo objeto. + +**Manutenibilidade:** +Fraca no médio prazo. + +### Opcao B - Criar facades de domínio em torno do SystemOS + +**Abordagem:** +Criar facades estreitas por domínio, expostas como acesso semântico: + +```text +os.lifecycle().suspend_task(...) +os.fs().mount(...) +os.window().set_focus(...) +``` + +Ou, se o design permitir sem duplicar ownership: + +```text +os.lifecycle.suspend_task(...) +os.fs.mount(...) +os.window.set_focus(...) +``` + +As facades seriam views/handles sobre os campos internos do `SystemOS`, não +owners independentes. + +**Vantagens:** +- deixa a raiz do OS menor; +- agrupa API por domínio; +- torna mais claro o que é lifecycle, fs, window, memcard e VM; +- ajuda a esconder managers internos; +- reduz a chance de firmware coordenar detalhes por fora. + +**Custos / Riscos:** +- exige decidir padrão de borrowing; +- pode adicionar tipos pequenos e boilerplate; +- `os.lifecycle.bla()` como campo direto pode ser difícil se a facade precisar + acessar `task_manager` e `process_manager` que vivem no mesmo `SystemOS`; +- talvez precise começar com métodos `os.lifecycle()` em vez de campos públicos. + +**Manutenibilidade:** +Forte se as facades forem views estreitas e não novos owners. + +### Opcao C - Criar services owners independentes dentro do SystemOS + +**Abordagem:** +Mover estado e lógica para structs owned diretamente: + +```text +SystemOS + lifecycle: LifecycleService + fs: FileSystemService + window: WindowService +``` + +Cada service seria owner do seu próprio estado ou de parte dele. + +**Vantagens:** +- aproxima o shape desejado `os.lifecycle.bla()`; +- reduz métodos no root; +- pode simplificar alguns domínios autocontidos. + +**Custos / Riscos:** +- lifecycle precisa coordenar task/process, então ownership separado pode criar + borrow/coordenação mais difícil; +- filesystem hoje cruza VM syscall state, `VirtualFS`, `FsState`, handles e + logging; +- pode reabrir decisões de ownership que acabaram de estabilizar; +- risco de mover estado cedo demais para caber numa estética de API. + +**Manutenibilidade:** +Boa para domínios autocontidos, arriscada para lifecycle neste momento. + +## Sugestao / Recomendacao + +A direção recomendada é **Opção B: facades de domínio como views estreitas sobre +o `SystemOS`**. + +O corte recomendado é: + +```text +SystemOS + lifecycle() + set_foreground_task + suspend_task + resume_task + close_task + crash_task + + sessions() + create_vm_game_task + create_vm_shell_task + create_native_shell_task + + vm() + initialize + tick + + fs() + mount + open + read + write + close + + window() + add_window + set_focus + focused_window + close_window + + log(...) +``` + +E evitar que a raiz acumule: + +```text +suspend_task +resume_task +close_task +crash_task +mount_fs +initialize_vm +tick_vm +create_vm_game_task +create_vm_shell_task +create_native_shell_task +window_manager direto +task_manager direto +process_manager direto +vm_runtime direto +fs direto +memcard direto +``` + +Para Rust, o primeiro corte provavelmente deve usar métodos de acesso que +retornam views: + +```rust +os.lifecycle().suspend_task(task_id) +os.fs().mount(backend) +os.window().set_focus(window_id) +``` + +Isso é menos bonito que campo direto, mas evita congelar ownership errado. Se +mais tarde algum domínio puder virar service owner real, podemos migrar para +campo direto sem mudar a semântica. + +Logging pode permanecer na raiz: + +```rust +os.log(...) +``` + +Motivo: logging é transversal, curto, usado por várias etapas do firmware, e não +carrega sozinho uma política complexa de estado. + +## Perguntas em Aberto + +- [x] Queremos a sintaxe ideal `os.lifecycle.bla()` mesmo que isso force + services owners reais, ou aceitamos `os.lifecycle().bla()` como primeira forma + borrow-friendly? quando escrevi os.lifecycle.bla() eu queria mesmo era os.lifecycle().bla() +- [x] Quais domínios entram no primeiro corte: só `lifecycle` e `fs`, ou também + `window`? nao precisamos criar nada, mas lifecycle, fs, window e vm sao easy wins no meu ponto de vista +- [x] `create_vm_game_task` e `create_vm_shell_task` pertencem a + `os.lifecycle()`, a `os.processes()/os.tasks()`, ou a um futuro domínio + `os.apps()/os.sessions()`? vamos de os.session() para esses. +- [x] `tick_vm` e `initialize_vm` devem ficar temporariamente na raiz, ou já + entrar em `os.vm()`? isso, os.vm(). +- [x] Campos como `task_manager`, `process_manager`, `window_manager`, + `vm_runtime`, `fs`, `memcard` devem deixar de ser públicos no mesmo corte ou + em planos graduais? eu nao os deixaria publicos desde jah, isso forca a politica de facades dentro de system os. +- [x] Como preservar testes sem criar APIs públicas só para inspeção? Testes devem ser feitos nos subdomínios; SystemOS só testa composição e coordenação que não pertence isoladamente a um domínio. + +## Resolucao Proposta + +A agenda deve fechar pela **Opção B**. + +O `SystemOS` continua sendo o owner e boundary de coordenação, mas sua superfície +pública deve ser compartimentalizada em facades de domínio. A forma normativa +inicial deve ser por métodos que retornam views borrow-friendly: + +```rust +os.lifecycle().suspend_task(task_id) +os.sessions().create_vm_game_task(app_id, title) +os.vm().initialize(vm, cartridge) +os.fs().mount(backend) +os.window().set_focus(window_id) +os.log(level, source, tag, msg) +``` + +A sintaxe com campo direto (`os.lifecycle.suspend_task(...)`) não é requisito +deste corte. A intenção semântica é domínio explícito; a forma prática inicial +deve respeitar ownership e borrowing em Rust. + +Domínios do primeiro corte: + +- `lifecycle()`: lifecycle semântico de task/process. +- `sessions()`: criação de tasks/processos de jogo e shell. +- `vm()`: inicialização e tick da VM. +- `fs()`: filesystem operacional. +- `window()`: operações mínimas de janela/foco. +- `log(...)`: permanece na raiz como operação transversal. + +Campos internos como `task_manager`, `process_manager`, `window_manager`, +`vm_runtime`, `fs`, `fs_state`, `memcard`, `open_files` e `next_handle` devem +deixar de ser públicos já neste corte, salvo se um plan específico demonstrar +necessidade temporária de migração. A política desejada é forçar acesso por +facades dentro do `SystemOS`. + +Testes devem migrar para os subdomínios quando estiverem validando comportamento +de domínio. `SystemOS` deve testar apenas composição e coordenação que realmente +não pertence isoladamente a um domínio. + +## Criterio para Encerrar + +Esta agenda pode virar decisão quando fecharmos: + +- qual forma de facade será normativa: campo direto, método view, ou service + owner; **resolvido: método view borrow-friendly.** +- quais domínios entram no primeiro corte; + **resolvido: lifecycle, sessions, vm, fs, window e log na raiz.** +- quais APIs permanecem no root; + **resolvido: `new`/construção e `log(...)`; demais APIs devem migrar para + facades.** +- se campos internos deixam de ser públicos agora ou em ondas; + **resolvido: deixar de ser públicos já no corte, com exceção transitória + somente se plan demonstrar necessidade.** +- como lifecycle, fs e window serão acessados por firmware, Hub e testes. + **resolvido: por facades; testes de domínio nos subdomínios.** + +## Proximo Passo + +Esta agenda está pronta para decisão normativa se a resolução proposta for +aceita. diff --git a/discussion/workflow/decisions/DEC-0026-systemos-domain-facades.md b/discussion/workflow/decisions/DEC-0026-systemos-domain-facades.md new file mode 100644 index 00000000..f6bf6cc3 --- /dev/null +++ b/discussion/workflow/decisions/DEC-0026-systemos-domain-facades.md @@ -0,0 +1,189 @@ +--- +id: DEC-0026 +ticket: system-os-domain-facades +title: SystemOS Domain Facades +status: accepted +created: 2026-05-15 +ref_agenda: AGD-0034 +tags: [runtime, os, services, api-surface, lifecycle, fs] +--- + +## Status + +Accepted. Esta decisão foi aceita em 2026-05-15 e passa a ser referência +normativa para compartimentalizar a superfície pública do `SystemOS`. + +## Contexto + +`DEC-0024` consolidou `SystemOS` como owner de serviços do Prometeu OS. +`DEC-0025` colocou o lifecycle de `Task` e `Process` sob autoridade do +`SystemOS`. + +Essas decisões estão corretas em termos de ownership, mas fizeram a raiz do +`SystemOS` crescer como superfície pública. Hoje a raiz mistura runtime VM, +filesystem, memcard, window management, lifecycle, managers internos, handles +operacionais e helpers de criação de tasks/processos. + +Esta decisão não muda o ownership: `SystemOS` continua sendo o boundary do OS. +O que muda é a forma normativa de acesso aos domínios. + +## Decisao + +`SystemOS` SHALL expose OS behavior through domain facades. + +The canonical first-wave access shape SHALL be method-based, borrow-friendly +views: + +```rust +os.lifecycle().suspend_task(task_id) +os.sessions().create_vm_game_task(app_id, title) +os.vm().initialize(vm, cartridge) +os.fs().mount(backend) +os.window().set_focus(window_id) +os.log(level, source, tag, msg) +``` + +Direct field syntax such as `os.lifecycle.suspend_task(...)` is NOT required in +this wave. Domain clarity is normative; direct field ownership is not. + +The first-wave `SystemOS` root SHALL keep only minimal root operations: + +```text +SystemOS + new(...) + log(...) + lifecycle() + sessions() + vm() + fs() + window() +``` + +`log(...)` MAY remain on the root because logging is a cross-cutting operation +used by multiple firmware and OS domains. + +The first-wave domain surface SHALL be: + +```text +lifecycle() + set_foreground_task + suspend_task + resume_task + close_task + crash_task + +sessions() + create_vm_game_task + create_vm_shell_task + create_native_shell_task + +vm() + initialize + tick + +fs() + mount + open + read + write + close + +window() + add_window + set_focus + focused_window + close_window +``` + +Internal service state SHALL NOT remain public on `SystemOS` once the +corresponding facade exists. This includes: + +- `task_manager` +- `process_manager` +- `window_manager` +- `vm_runtime` +- `fs` +- `fs_state` +- `memcard` +- `open_files` +- `next_handle` + +Plans MAY use temporary transitional access only when needed to keep migrations +small, but the completed first-wave facade migration MUST remove direct public +access for migrated domains. + +## Rationale + +`SystemOS` should remain the owner of OS services, but callers should not see it +as a bag of unrelated fields and root methods. Domain facades make the API read +like an OS surface: + +- lifecycle operations live under lifecycle; +- session construction lives under sessions; +- VM execution lives under vm; +- filesystem operations live under fs; +- window operations live under window; +- logging remains root-level because it cuts across domains. + +Method-based facades are preferred over direct fields in this wave because they +preserve Rust borrowing flexibility. A facade can be a temporary view over +multiple internal fields without forcing premature service ownership splits. + +This also protects `DEC-0025`: lifecycle remains the semantic coordinator for +`TaskState` and `ProcessState`, but callers reach it through +`os.lifecycle()`, not through root methods or direct manager access. + +## Invariantes / Contrato + +- `SystemOS` MUST remain the OS ownership and coordination boundary. +- Facades MUST be views or handles over `SystemOS` internals unless a later + decision explicitly promotes a domain to an independently owned service. +- Facades MUST NOT duplicate state. +- Root-level `SystemOS` API MUST stay minimal. +- Lifecycle operations MUST move from root-level `SystemOS` methods to + `os.lifecycle()`. +- Session creation helpers MUST move to `os.sessions()`. +- VM initialization and ticking MUST move to `os.vm()`. +- Filesystem operations MUST move to `os.fs()`. +- Window operations MUST move to `os.window()`. +- Logging MAY remain as `os.log(...)`. +- Firmware, Hub and tests SHOULD use facades instead of direct internal fields. +- Tests for domain behavior SHOULD live at the facade/domain level. +- `SystemOS` tests SHOULD focus on composition and cross-domain coordination. + +## Impactos + +- `crates/console/prometeu-system/src/os/` should gain facade/view types for + lifecycle, sessions, VM, filesystem and window domains. +- Existing root methods such as `suspend_task`, `resume_task`, `close_task`, + `crash_task`, `initialize_vm`, `tick_vm`, `mount_fs`, `create_vm_game_task`, + `create_vm_shell_task` and `create_native_shell_task` should migrate behind + domain facades. +- Direct access to managers and service fields from firmware, Hub and tests + should be removed or narrowed. +- Filesystem state may require a dedicated facade because it spans `VirtualFS`, + `FsState`, file handles, memcard-adjacent state and logging. +- Window access should move away from `os.window_manager` to `os.window()`. +- Specs do not need immediate updates unless these facades become part of a + published external API. + +## Referencias + +- Agenda: `AGD-0034` +- Related decision: `DEC-0024` +- Related decision: `DEC-0025` + +## Propagacao Necessaria + +- Plans: create small plans for lifecycle facade, sessions/vm facade, fs facade, + window facade and internal field encapsulation. +- Code: update `prometeu-system`, firmware, Hub and tests to use domain + facades. +- Tests: move lifecycle/session/fs/window assertions to domain-level tests where + possible. +- Discussion: keep this decision separate from future decisions about true + service ownership splits. + +## Revisao + +- 2026-05-15: Initial accepted decision from `AGD-0034`. diff --git a/discussion/workflow/plans/PLN-0058-systemos-domain-facades-first-wave.md b/discussion/workflow/plans/PLN-0058-systemos-domain-facades-first-wave.md new file mode 100644 index 00000000..0ac1a228 --- /dev/null +++ b/discussion/workflow/plans/PLN-0058-systemos-domain-facades-first-wave.md @@ -0,0 +1,223 @@ +--- +id: PLN-0058 +ticket: system-os-domain-facades +title: SystemOS Domain Facades First Wave +status: open +created: 2026-05-15 +ref_decisions: [DEC-0026] +tags: [runtime, os, services, api-surface, lifecycle, fs] +--- + +## Briefing + +Implement the first wave of `SystemOS` domain facades required by `DEC-0026`. +`SystemOS` remains the OS ownership boundary, but callers must access behavior +through domain views instead of root-level methods or public internal fields. + +## Source Decisions + +- `DEC-0026`: `SystemOS` must expose method-based domain facades for lifecycle, + sessions, VM, filesystem and window operations, while keeping `log(...)` on + the root. +- Related: `DEC-0025` keeps lifecycle coordination under `SystemOS`. +- Related: `DEC-0024` keeps services owned or mediated by `SystemOS`. + +## Target + +Create these first-wave access shapes: + +```rust +os.lifecycle().suspend_task(task_id) +os.sessions().create_vm_game_task(app_id, title) +os.vm().initialize(vm, cartridge) +os.vm().tick(vm, signals, hw) +os.fs().mount(backend) +os.window().set_focus(window_id) +os.log(level, source, tag, msg) +``` + +After this plan, migrated domains must no longer require public direct access +to `task_manager`, `process_manager`, `window_manager`, `vm_runtime`, `fs`, +`fs_state`, `memcard`, `open_files` or `next_handle`. + +## Scope + +- Add facade/view types under `crates/console/prometeu-system/src/os/`. +- Add `SystemOS` methods: + - `lifecycle()` + - `sessions()` + - `vm()` + - `fs()` + - `window()` +- Move root lifecycle methods behind `lifecycle()`. +- Move task/process session creation behind `sessions()`. +- Move VM initialization/ticking/reset or execution helpers behind `vm()`. +- Move filesystem mount/open/read/write/close entry points behind `fs()` when + the operation exists at OS level. +- Move window operations behind `window()`. +- Keep `SystemOS::log(...)` at root. +- Migrate firmware, Hub and tests to facade access. +- Make migrated internal `SystemOS` fields private. + +## Out of Scope + +- Changing service ownership established by `DEC-0024`. +- Changing lifecycle semantics established by `DEC-0025`. +- Introducing `os.lifecycle` as a direct public field. +- Background lifecycle semantics. +- New filesystem syscall behavior beyond exposing existing OS-owned operations. +- Diagnostics/crash report persistence. +- Redesigning Hub UI or app switching. +- Replacing VM runtime tests that intentionally test `VirtualMachineRuntime` + directly. + +## Execution Plan + +1. Create facade modules and view types. + - Target files: + - `crates/console/prometeu-system/src/os/mod.rs` + - `crates/console/prometeu-system/src/os/system_os.rs` + - new facade modules under `crates/console/prometeu-system/src/os/` + - Define mutable view structs such as `LifecycleFacade<'a>`, + `SessionsFacade<'a>`, `VmFacade<'a>`, `FsFacade<'a>` and + `WindowFacade<'a>`. + - Each facade should borrow the needed `SystemOS` internals and must not own + duplicated state. + +2. Add `SystemOS` facade accessors. + - Add `SystemOS::lifecycle(&mut self) -> LifecycleFacade<'_>`. + - Add `SystemOS::sessions(&mut self) -> SessionsFacade<'_>`. + - Add `SystemOS::vm(&mut self) -> VmFacade<'_>`. + - Add `SystemOS::fs(&mut self) -> FsFacade<'_>`. + - Add `SystemOS::window(&mut self) -> WindowFacade<'_>`. + - Keep `SystemOS::new(...)` and `SystemOS::log(...)` on the root. + +3. Move lifecycle operations. + - Target existing logic in `crates/console/prometeu-system/src/os/system_os.rs`. + - Move or delegate: + - `set_foreground_task` + - `suspend_task` + - `resume_task` + - `close_task` + - `crash_task` + - The facade must preserve typed `LifecycleError` behavior. + - Callers should use `os.lifecycle().crash_task(...)` rather than + `os.crash_task(...)`. + +4. Move session creation operations. + - Move or delegate: + - `create_vm_game_task` + - `create_vm_shell_task` + - `create_native_shell_task` + - These operations may call the lifecycle facade internally to foreground + newly created tasks. + - Firmware should use `ctx.os.sessions().create_vm_game_task(...)` and + `ctx.os.sessions().create_vm_shell_task(...)`. + +5. Move VM operations. + - Move or delegate: + - `initialize_vm` as `os.vm().initialize(...)` + - `tick_vm` as `os.vm().tick(...)` + - Include reset access if needed to remove direct `os.vm_runtime.reset(...)` + from firmware. + - Preserve VM runtime behavior and logging. + +6. Move filesystem operations. + - Move or delegate existing root filesystem operations: + - `mount_fs` as `os.fs().mount(...)` + - `unmount_fs` if still present, even though `DEC-0026` only names + mount/open/read/write/close for the target surface. + - Expose OS-owned open/read/write/close only if those operations already have + a suitable service-level implementation; otherwise leave them as explicit + follow-up within the facade module without inventing new behavior. + - Keep filesystem state private to `SystemOS`/facade internals. + +7. Move window operations. + - Target: + - `crates/console/prometeu-system/src/services/window_manager.rs` + - `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs` + - firmware launch tests and cartridge loading. + - Provide facade operations: + - `add_window` + - `set_focus` + - `focused_window` + - `close_window` + - Add any narrow helper needed to preserve existing behavior such as removing + all windows, but keep it under `window()` rather than exposing + `window_manager`. + +8. Encapsulate migrated fields. + - In `SystemOS`, remove `pub` from migrated internals once callsites have + moved: + - `vm_runtime` + - `process_manager` + - `task_manager` + - `window_manager` + - `fs` + - `fs_state` + - `memcard` + - `open_files` + - `next_handle` + - Keep `log_service` private unless a plan proves a public log handle is + required. + - Avoid adding compatibility root methods for the old surface. + +9. Update tests. + - Move `SystemOS` lifecycle tests to facade calls. + - Update firmware tests to observe state through facades or domain-specific + inspection helpers rather than direct internal fields. + - Preserve direct `VirtualMachineRuntime` tests where they test the VM runtime + service itself, not `SystemOS`. + +## Acceptance Criteria + +- `SystemOS` exposes `lifecycle()`, `sessions()`, `vm()`, `fs()` and `window()`. +- Root `SystemOS` keeps `new(...)` and `log(...)`. +- Lifecycle callsites use `os.lifecycle()`. +- Session creation callsites use `os.sessions()`. +- VM initialization/tick/reset callsites use `os.vm()`. +- Window callsites use `os.window()`. +- Existing root methods migrated by this plan are removed or made private. +- Migrated internal fields no longer remain public on `SystemOS`. +- No facade duplicates service state. +- Existing behavior remains unchanged. + +## Tests / Validation + +- Run `cargo test -p prometeu-system`. +- Run `cargo test -p prometeu-firmware`. +- Run `discussion validate`. +- Confirm with search that migrated callsites no longer use: + - `os.task_manager` + - `os.process_manager` + - `os.window_manager` + - `os.vm_runtime` + - `os.suspend_task` + - `os.resume_task` + - `os.close_task` + - `os.crash_task` + - `os.initialize_vm` + - `os.tick_vm` + - `os.create_vm_game_task` + - `os.create_vm_shell_task` + +## Risks + +- Borrowing may require facades to expose narrow methods rather than returning + long-lived mutable references. Keep facades short-lived and method-based. +- Some tests currently inspect internal fields directly. Prefer domain-level + inspection helpers over keeping fields public. +- Filesystem `open/read/write/close` may not all exist as OS-level operations + yet. Do not invent new filesystem semantics while implementing the facade. +- Removing all public internals in one change can be broad. If a field cannot be + hidden without unrelated redesign, document the temporary exception in the + implementation and leave a follow-up plan. + +## Affected Artifacts + +- `crates/console/prometeu-system/src/os/**` +- `crates/console/prometeu-system/src/programs/prometeu_hub/**` +- `crates/console/prometeu-system/src/services/window_manager.rs` +- `crates/console/prometeu-firmware/src/firmware/**` +- `discussion/index.ndjson` +- `discussion/workflow/plans/PLN-0058-systemos-domain-facades-first-wave.md`