Three parallel audits (quality, performance, security) identified issues across the codebase. This commit addresses all remaining findings: - Replace busy-loop polling in run_command with child.wait() + timeout thread - Canonicalize ~/.face and AccountsService avatar paths to prevent symlink abuse - Add detect_locale_with() DI function for testable locale detection - Move config I/O from activate() to main() to avoid blocking GTK main loop - Validate background_blur range (0–200), reject invalid values with warning - Remove embedded wallpaper from GResource — moonarch provides it via filesystem (binary size ~3.2MB → ~1.3MB)
81 lines
5.9 KiB
Markdown
81 lines
5.9 KiB
Markdown
# Decisions
|
||
|
||
Architectural and design decisions for Moonset, in reverse chronological order.
|
||
|
||
## 2026-03-28 – Remove wallpaper from GResource bundle
|
||
|
||
- **Who**: Ragnar, Dom
|
||
- **Why**: All three Moon projects (moonset, moongreet, moonlock) embedded a 374kB fallback wallpaper in the binary via GResource. Moonarch already installs `/usr/share/moonarch/wallpaper.jpg` at system setup time, making the embedded fallback unnecessary dead weight (~2MB in binary size).
|
||
- **Tradeoffs**: If `/usr/share/moonarch/wallpaper.jpg` is missing and no user config exists, moonset shows a solid CSS background instead of a wallpaper. Acceptable — the power menu is functional without a wallpaper image.
|
||
- **How**: Removed `wallpaper.jpg` from GResource XML and resources directory. `resolve_background_path` returns `Option<PathBuf>`. All wallpaper-related functions handle `None` gracefully. Binary size dropped from ~3.2MB to ~1.3MB.
|
||
|
||
## 2026-03-28 – Switch from env_logger to systemd-journal-logger
|
||
|
||
- **Who**: Ragnar, Dom
|
||
- **Why**: moonlock and moongreet already use systemd-journal-logger. moonset used env_logger which writes to stderr — not useful for a GUI app launched via keybind. Journal integration enables `journalctl -t moonset` and consistent troubleshooting across all three Moon projects.
|
||
- **Tradeoffs**: Requires systemd at runtime. Graceful fallback to eprintln if journal logger fails. Acceptable since Moonarch targets systemd-based Arch Linux.
|
||
- **How**: Replace `env_logger` dep with `systemd-journal-logger`, add `setup_logging()` with `MOONSET_DEBUG` env var for debug-level output. Same pattern as moonlock/moongreet.
|
||
|
||
## 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 – GPU blur via GskBlurNode replaces CPU blur
|
||
|
||
- **Who**: Ragnar, Dom
|
||
- **Why**: CPU-side Gaussian blur (`image` crate) blocked startup and added caching complexity. moonlock already migrated to GPU blur.
|
||
- **Tradeoffs**: GPU blur quality is slightly different (box-blur approximation vs true Gaussian), acceptable for wallpaper backgrounds. Removes `image` crate dependency entirely. No disk cache needed.
|
||
- **How**: `Snapshot::push_blur()` + `GskRenderer::render_texture()` on `connect_realize`. Blur happens once on the GPU when the widget gets its renderer. Symmetric with moonlock and moongreet.
|
||
|
||
## 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"])`.
|