3.2 KiB
| id | ticket | title | created | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| LSN-0043 | system-os-domain-facades | SystemOS Domain Facades | 2026-05-15 |
|
Context
SystemOS became the owner and mediator for core OS services: VM runtime,
lifecycle, filesystem, memcard, window management, task/process state and
logging. That ownership boundary is correct, but exposing every service field
and operation on the root made the OS surface too broad.
The solution was not to split ownership back out of SystemOS; it was to split
the public access surface into short-lived domain views.
Key Decisions
Use method-based domain facades
What: SystemOS exposes domain entry points such as:
os.lifecycle()
os.sessions()
os.vm()
os.fs()
os.window()
Each accessor returns a borrow-friendly facade over SystemOS internals.
Why: Direct fields such as os.lifecycle.suspend_task(...) look attractive,
but they force ownership shape too early. Method-based views preserve Rust
borrowing flexibility while still making the domain boundary explicit.
Trade-offs: Callers write os.lifecycle().suspend_task(...) instead of
os.lifecycle.suspend_task(...). The extra call is worth the cleaner ownership
model.
Keep logging on the root
What: os.log(...) remains root-level.
Why: Logging is cross-cutting, short and used by multiple domains. It is not a broad policy surface in the same way lifecycle, VM, fs or window management are.
Trade-offs: The root is not empty, but it remains intentionally small.
Hide migrated internals
What: Direct access to internal fields such as task/process managers, window manager and VM runtime should disappear once the corresponding facade exists.
Why: Public internals let callers bypass OS policy. Facades force callers to use the semantic boundary instead of stitching together lower-level services.
Trade-offs: Tests need domain-level inspection helpers instead of reaching into raw fields. That is better than keeping production internals public for test convenience.
Patterns and Algorithms
Use a short-lived view when an operation needs access to several SystemOS
fields:
os.lifecycle().crash_task(task_id, Some(&report));
os.vm().tick(vm, signals, hw);
os.window().set_focus(window_id);
The facade should borrow SystemOS or the necessary internals; it must not own
duplicated state. If a domain later becomes a true independently owned service,
that should be a separate decision.
Pitfalls
- Do not solve a wide root by moving ownership out of
SystemOSprematurely. - Do not keep raw managers public just because tests need inspection.
- Do not make facades long-lived when short-lived method calls avoid borrow pressure.
- Do not invent new filesystem behavior while creating an
fs()facade; expose existing behavior first.
Takeaways
- Ownership boundary and public API shape are separate architectural questions.
SystemOScan remain the owner while exposing a narrower domain-oriented API.- Method-based facades are a pragmatic Rust shape for OS domains that coordinate multiple internal services.
- A small root API makes OS policy harder to bypass and easier to document.