moonset/DECISIONS.md
nevaforget 412ed159a4 fix: address audit findings — blur channel mismatch, logout quit, config error logging
- Fix BGRA→RGBA channel swap in apply_blur so image::RgbaImage semantics
  match the actual pixel data from GDK texture download
- Logout now calls app.quit() like lock does, via new quit_after field on
  ActionDef (replaces fragile magic string comparison)
- Log TOML parse errors to stderr instead of silently ignoring
- Remove pointless zlib compression of JPEG wallpaper in GResource
- Add tests for quit_after behavior and config error handling
2026-03-28 21:39:34 +01:00

67 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Decisions
Architectural and design decisions for Moonset, in reverse chronological order.
## 2026-03-28 Replace action name dispatch with `quit_after` field
- **Who**: Hekate, Dom
- **Why**: Post-action behavior (quit the app or not) was controlled by comparing `action_name == "lock"` — a magic string duplicated from the action definition. Renaming an action would silently break the dispatch.
- **Tradeoffs**: Adds a field to `ActionDef` that most actions set to `false`. Acceptable because it makes the contract explicit and testable.
- **How**: `ActionDef.quit_after: bool``true` for lock and logout, `false` for hibernate/reboot/shutdown.
## 2026-03-28 Optional background blur via `image` crate
- **Who**: Hekate, Dom
- **Why**: Blurred wallpaper as background is a common UX pattern for overlay menus
- **Tradeoffs**: Adds `image` crate dependency (~15 transitive crates); CPU-side Gaussian blur at load time adds startup latency proportional to image size and sigma. Acceptable because blur runs once and the texture is shared across monitors.
- **How**: `load_background_texture(bg_path, blur_radius)` loads texture, optionally applies `imageops::blur()`, returns `gdk::Texture`. Config option `background_blur: Option<f32>` in TOML.
## 2026-03-28 Use absolute paths for system binaries
- **Who**: Hekate, Dom
- **Why**: Security audit flagged PATH hijacking risk — relative binary names allow a malicious `$PATH` entry to intercept `systemctl`, `loginctl`, etc.
- **Tradeoffs**: Hardcoded paths reduce portability to non-Arch distros where binaries may live elsewhere (e.g. `/sbin/`). Acceptable because Moonarch targets Arch Linux exclusively.
- **How**: All five power action wrappers now use `/usr/bin/` prefixed paths.
## 2026-03-28 Implement power action timeout via try_wait polling
- **Who**: Hekate, Dom
- **Why**: `POWER_TIMEOUT` and `PowerError::Timeout` were declared but never wired up. A hanging `systemctl hibernate` (e.g. blocked NFS mount) would freeze the power menu indefinitely.
- **Tradeoffs**: Polling with `try_wait()` + 100ms sleep is slightly less efficient than a dedicated timeout crate, but avoids adding a dependency for a single use case.
- **How**: `run_command` now polls `child.try_wait()` against a 30s deadline, kills the child on timeout.
## 2026-03-28 Centralize GRESOURCE_PREFIX
- **Who**: Hekate, Dom
- **Why**: The string `/dev/moonarch/moonset` was duplicated in `config.rs`, `users.rs`, and as literal strings in `panel.rs` and `main.rs`. Changing the application ID would require edits in 4+ locations.
- **Tradeoffs**: Modules now depend on `crate::GRESOURCE_PREFIX` — tighter coupling to main.rs, but acceptable for an internal constant.
- **How**: Single `pub(crate) const GRESOURCE_PREFIX` in `main.rs`, referenced everywhere else.
## 2026-03-28 Remove journal.md
- **Who**: Hekate, Dom
- **Why**: One-time development notes from the Rust rewrite, never updated after initial session. Overlapped with memory system and git history.
- **Tradeoffs**: Historical context lost from the file, but the information is preserved in git history and the memory system.
- **How**: Deleted. Useful technical learnings migrated to persistent memory.
## 2026-03-27 OVERLAY layer instead of TOP
- **Who**: Hekate, Dom
- **Why**: Waybar occupies the TOP layer. The power menu must appear above it.
- **Tradeoffs**: OVERLAY is the highest layer — nothing can render above moonset while it's open. This is intentional for a session power menu.
- **How**: `setup_layer_shell` uses `gtk4_layer_shell::Layer::Overlay` for the panel window.
## 2026-03-27 Lock without confirmation
- **Who**: Hekate, Dom
- **Why**: Lock is immediately reversible (just unlock). All other actions (logout, hibernate, reboot, shutdown) are destructive or disruptive.
- **Tradeoffs**: One less click for the most common action. Risk of accidental lock is negligible since unlocking is trivial.
- **How**: `ActionDef.needs_confirm = false` for lock; all others require inline confirmation.
## 2026-03-27 Niri-specific logout via `niri msg action quit`
- **Who**: Hekate, Dom
- **Why**: Moonarch is built exclusively for the Niri compositor. Generic Wayland logout mechanisms don't exist — each compositor has its own.
- **Tradeoffs**: Hard dependency on Niri. If the compositor changes, `power::logout()` must be updated.
- **How**: `Command::new("/usr/bin/niri").args(["msg", "action", "quit"])`.