The redbear-* logging-unify refactor (println/eprintln -> log::*) left three
mechanical corruptions, caught by --check-sweep:
1. log::MACRO!(); (empty call + spurious ;, args dangling) -> log::MACRO!(
2. log::MACRO!(<args>)); (one extra trailing paren) -> log::MACRO!(<args>);
3. use log::{..}; inserted INSIDE a 'use std::{' block -> moved out
Fixed across redbear-greeter/notifications/session-launch/statusnotifierwatcher/
upower (string-aware paren-balance sweep; balanced nested-paren calls untouched).
Separately, the 'tokio minimal' refactor left redbear-notifications and
redbear-statusnotifierwatcher using tokio::signal::ctrl_c/unix without the
tokio 'signal' feature (compile break). Per redbear-upower's documented finding,
tokio::signal::unix page-faults on Redox (relibc lacks the signal-handler
registration path) and Redox manages daemon lifecycle via the init system, not
POSIX signals. So the correct fix is NOT to re-add the feature but to drop the
signal-based shutdown entirely — the daemon holds its shutdown channel open and
runs until init stops it. Applied to all four signal-using daemons
(notifications, statusnotifierwatcher, udisks, polkit) and removed the now-unused
tokio 'signal' feature from udisks/polkit for consistency with upower.
- redbear-netctl: route --boot (and other manual commands) around clap so
CommonArgs::parse no longer aborts with 'unexpected argument --boot'
(12_netctl.service boot-time profile application was failing).
- redbear-keymapd: a missing /etc/keymaps is normal on mini (built-in
keymaps cover the console) — log INFO, not ERROR, on NotFound.
- driver-manager: fix 'options loadeds' plural typo; log read_dir errno on
PCI enumeration failure instead of an opaque IoError.
- redbear-mini: ship a 05_firmware-loader.service stub so the bluetooth
units' weak dep resolves (was 'unit not found' x2 per boot).
The shipped /lib/drivers.d/10-network.toml scopes vendor+class matches to
specific device ids with `device = [0x8168, 0x8169]` (rtl8168d) and a
42-id ixgbed list — the documented, intended form. But RawDriverMatch
parsed `device` as a single u16, so the list form failed to deserialize
("invalid type: sequence, expected u16") and took the whole file down,
leaving driver-manager with zero network drivers loaded — including
virtio-netd, so no network came up at all even in QEMU.
Parse `device` as scalar-or-list (U16OrList) and fan each raw match out
to one DriverMatch per id (an OR alternative carrying the shared
vendor/class/subclass constraints). Scalar and device-less matches keep
their previous 1:1 behaviour. Adds regression tests for both forms.
Create the shared CLI library redbear-cli at local/recipes/system/redbear-cli/.
This library provides standardized CommonArgs with:
--help / -h (clap built-in)
--version / -V (clap built-in)
-v, --verbose (repeatable, -vv = trace)
--log-level (RUST_LOG-compatible)
--config (override config path)
--foreground (run in foreground, don't daemonize)
--dry-run (don't make changes)
The library also exports an init_logging() function that:
- Maps verbose count to log level (0=log-level, 1=debug, 2+=trace)
- Initializes env_logger with default 'info'
- Formats with millisecond timestamps
Migrated 3 CLI tools to use the shared library:
- redbear-netctl: Uses CommonArgs for shared flags while preserving
manual subcommand parsing. existing test suite all passes.
- redbear-mtr: Converted to clap derive with CommonArgs + tool args.
-v, --version, --help, --log-level, --config, --foreground work.
- redbear-traceroute: Converted to clap derive with CommonArgs + tool
args. Same shared flags work.
Wired into config/redbear-mini.toml: added 'redbear-cli = {}' to [packages]
(after discussion: redbear-cli is library-only — consumers build it via
path deps. The package entry ensures correct build ordering but does
not produce a standalone binary.)
Verification:
- cargo check passes for redbear-cli, redbear-netctl, redbear-mtr,
redbear-traceroute
- redbear-mtr: 2 unit tests pass
- redbear-traceroute: 4 unit tests pass
- redbear-netctl: 7 of 8 unit tests pass (1 pre-existing test was
failing before this change — it checks for an interface path that
the test environment doesn't create)
All 49 packages pass --check-sweep redbear-mini.
The single production-code panic in the redbear-* codebase was in
StubBackend::from_env() (backend.rs:192). It panicked when the
REDBEAR_BTCTL_STUB_ADAPTERS env var contained an invalid Bluetooth adapter
name.
Previously:
- from_env() returned Self (infallible)
- build_backend() returned Box<dyn Backend>
- main() returned anyhow::Result<()>
After:
- from_env() renamed to try_from_env() -> Result<Self, String>
- build_backend() returns anyhow::Result<Box<dyn Backend>>
- main() call sites use '?' to propagate errors
- Adapter name validation now returns Err instead of crashing the daemon
The panic was the ONLY production-code panic across all 5 redbear-*
programs that this phase was scoped for. The other 13 panics are in
test code (#[cfg(test)] modules), which is idiomatic Rust testing
practice and does not need modification.
cargo check --manifest-path source/Cargo.toml passes cleanly.
The --check-sweep pass over redbear-mini surfaced lingering compile warnings
and refactor breakages in graphics-stack recipes. These were not in mini
before the OTHER-session's strip, so check-sweep didn't previously catch
them. Now that they need to compile cleanly (e.g. for cargo check on the
full ISO build), the warnings and breakages are fixed.
Touched programs (8):
- redbear-btusb: refactor main.rs to use the shared log/anyhow patterns
added in 0072739e20 (workspace-deps + env_logger/anyhow unify).
- redbear-iwlwifi: bridge + main.rs refactor for log/thiserror. mld/key.rs
picks up the same pattern. Cargo.toml picks up workspace dependencies.
- redbear-greeter: main.rs small refactor for log consistency.
- redbear-polkit: main.rs and Cargo.toml aligned with workspace pattern.
- redbear-statusnotifierwatcher: main.rs log refactor.
- redbear-udisks: main.rs + interfaces.rs + inventory.rs + Cargo.toml aligned
with workspace pattern.
- redbear-compositor: main.rs + Cargo.toml aligned with workspace pattern.
Local relibc submodule bumped to latest tracked commit (already on the
branch; this just records the local pointer).
Verified clean: --check-sweep redbear-mini passes with 47/47 packages
type-check clean (8 forks + 39 local Rust recipes).
No build-blockers. sync-versions.sh --check passes (76 Cat 1 crates, 0 drift).
After restoring the mini recipe set to HEAD (discarding agent working-tree
re-mutations), three recipes were still broken at the commit level from the
in-flight eprintln->log/env_logger refactor:
- btusb: extra ')' on two log::error! calls; added missing env_logger dep
- iwlwifi: multiple 'log::error!();' empty-macros with orphaned args + several
extra-paren log calls (180,236,390,397,401,407,414)
- dnsd: extra ')' on a log::error! call
All 41 text-only-mini local Rust recipes now cargo-check clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The in-flight logging/error-handling refactor left these 9 text-only-mini
recipes non-compiling. Completed it correctly:
- dangling parens from eprintln!(...) -> log::error!(...) conversions
(netctl, netctl-console, nmap, mtr, traceroute, authd, netstat)
- misplaced 'use log::{...};' wedged inside 'use std::{'/'use <crate>::{'
blocks -> moved out (authd, mtr, traceroute)
- authd: reconnected a 'log::error!();' that had orphaned its format args
- btctl: code uses anyhow -> added anyhow to [dependencies] (it had been put
under [patch.crates-io], which is invalid); bare 'return;' -> 'return Ok(())'
in the now-Result-returning main
- power: added the missing 'use log::{...}' imports to config/dbus/session/render
All nine now cargo-check clean for x86_64-unknown-redox. Committed to persist
against the working-tree reverter.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The eprintln!->log/env_logger conversion in redbear-phase{2-wayland,3-kwin,
4-kde}-check inserted 'use log;' INSIDE the 'use std::{ ... }' block, producing
'expected identifier, found keyword use' / 'unresolved imports std::r#use,
std::log' -> redbear-hwutils failed to cook. log::/env_logger:: are called by
full path (and log/env_logger are already deps), so the import is redundant;
removed the three stray lines. All hwutils bins compile.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bridge/scheme.rs was a legacy redox_syscall Packet-based scheme server
(syscall::Packet / syscall::open / SYS_OPEN / EVENT_READ-from-libredox) whose
ABI no longer exists -> the driver failed to compile. Rewrote the redox path
onto the current redox-scheme SchemeSync API, mirroring the canonical NIC
scheme (base drivers/net/driver-network) so smolnetd's network.* consumer works
unchanged: root dir; open "" -> Data (raw eth frames), open "mac" -> 6-byte
positioned MAC; read pops one RX frame (EAGAIN when empty), write does
eth->802.11->C TX submit; blocked readers woken via post_fevent(EVENT_READ).
Kept the self-contained non-blocking 1ms poll loop (also pumps bridge TX). Also
made the two extern "C" blocks (callback.rs, scheme.rs FFI)
for Rust 2024, and added redox-scheme as a redox-target dep. Compile-checked;
not yet hardware-validated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 2026-07-28 FIRST-CLASS CITIZEN POLICY was initially drafted with all 48
redbear-* recipes wired into redbear-mini. The operator corrected this:
MINI target includes just packages whicha are not related to graphics.
While FULL must contain all text+graphial packages.
So the corrected architecture is:
- redbear-mini = text-only binaries (24 original + a few more)
- redbear-full = ALL redbear-* (text + graphics, via inheritance + explicit
full-only entries)
Updated docs:
- REDBEAR-FIRST-CLASS-CITIZEN-POLICY.md: rewrote with the wiring table per
program classification (text-only binary / graphics binary / library-only /
hardware peripheral driver). Library-only recipes follow their consumers'
target: tui-theme (consumed by power/cub/tlc in mini) goes in mini;
hid-core/login-protocol/passwd (consumed by desktop-only programs) go in full.
- ORPHAN-STATUS.md: rewrote as 'Library-only Red Bear Crates' reference.
Documents the 4 library-only recipes, their consumers, and the config
they are wired into per the corrected policy.
- FIRMWARE-SUBSETS-DECISION.md: rewrote. All 5 firmware recipes (monolithic
+ 4 subsets) are now correctly classified as graphics-related and wired
into redbear-full (not mini). Original decision was to KEEP-ORPHAN them,
but the corrected FIRST-CLASS policy promotes them to first-class citizens
in redbear-full.
- REDBEAR-UFW-STATUS.md: rewrote. redbear-ufw is a text-only firewall prototype
and is wired into redbear-mini (the text-only target), not redbear-full.
The prototype is built on every canonical build invocation per the
FIRST-CLASS CITIZEN policy.
- 5 firmware README.md files: removed stale 'KEEP-ORPHAN' / 'STUB-DATA'
markers that were written before the corrected policy. Each now reads
'FIRST-CLASS CITIZEN (wired into config/redbear-full.toml [packages])'
per the corrected wiring.
All 48 redbear-* recipes remain reachable from at least one config:
- text-only binaries + their consumers' libraries in redbear-mini
- graphics binaries + library-only recipes for desktop consumers in redbear-full
- hardware peripherals in redbear-{wifi,bluetooth}-experimental.toml (inherited by full)
sync-versions.sh --check still passes (75 Cat 1 crates, 0 drift).
The 4 redbear-firmware-* recipes and redbear-driver-policy declared
[build] dependencies = ["driver-manager-config"], but no such package/recipe
exists anywhere -> repo cook aborts with 'Package driver-manager-config not
found' before building the image. The real driver-infrastructure package is
'driver-manager' (a cargo recipe, present in every config). The '-config' name
was planned but never created; the dep is only an ordering gate (these scripts
stage firmware blobs / policy TOMLs and don't consume config files at build
time). Redirected the dep to the existing 'driver-manager' package.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2A — Edition bumps (5 programs, edition 2021 → 2024):
- redbear-accessibility
- redbear-ime
- redbear-keymapd
- redbear-tui-theme
- redbear-compositor
Per AGENTS.md: 'edition = 2024' is mandatory for new Rust code. These 5
were the last stragglers on edition 2021 in the redbear-* scope.
Phase 2B — license + repository + description metadata (35 files):
All redbear-* source/Cargo.toml files now have:
license = 'MIT'
repository = 'https://gitea.redbearos.org/vasilito/RedBear-OS'
description = '<one-line purpose>'
103 fields added total across 35 files. redbear-tui-theme already had the
fields (skipped). redbear-hid-core already had license+description (only
got repository). No version fields modified.
Phase 2E — tokio minimal feature set (5 programs):
- redbear-notifications
- redbear-polkit
- redbear-sessiond
- redbear-statusnotifierwatcher
- redbear-udisks
Migrated from features=['full'] to:
default-features = false
features = ['rt', 'rt-multi-thread', 'macros', 'net', 'time', 'sync']
'features = ["full"]' pulls in signal-handler code that crashes on Redox.
The minimal set matches redbear-upower's existing pattern (already used
the right config). redbear-sessiond's vendored tokio patch
(local/patches/tokio/vendored) is unaffected — only the consumer feature
declaration changed, the [patch.crates-io] override still points to the
same vendored path.
Verified: 'features = ["full"]' returns 0 matches across the 5 target
programs. sync-versions.sh --check passes (75 Cat 1 crates, 0 drift).
Phase 1 critical fixes:
1. redbear-netctl-console/recipe.toml: add missing [package] name + version
fields. The recipe was silently dropped by the cookbook because it had
no [package] identity, breaking 'make r.redbear-netctl-console'.
2. redox-drm/recipe.toml: add missing [package] name + version. Same defect
class as redbear-netctl-console.
3. redbear-tui-theme/recipe.toml: create from scratch. The source/ crate
existed but no recipe.toml meant the cookbook never cooked it. Now wired
into redbear-mini (Phase 3).
4. redbear-ufw/recipe.toml + REDBEAR-UFW-STATUS.md: prototype in base fork
(local/sources/base/redbear-ufw/) previously had no recipe and no
documentation. Per AGENTS.md NEVER DELETE rule, the source is preserved
in base; a recipe is now created + a status doc explains the
intentionally-orphaned lifecycle (NEVER DELETE compliance).
5. Delete vestigial local/recipes/system/redbear-netstat/redbear-netstat/
nested directory (duplicate of source/, NOT consumed by build — pure
dead code).
First-class-citizen policy:
- REDBEAR-FIRST-CLASS-CITIZEN-POLICY.md: declares that every redbear-*
recipe is a first-class citizen of redbear-mini. No recipe may be left
unreachable from the build. This codifies the operator's earlier intent
statement that all redbear-* programs must be built.
- ORPHAN-STATUS.md: documents KEEP-ORPHAN recipes (library-only crates
consumed via Cargo path deps — correct pattern, not real orphans).
- FIRMWARE-SUBSETS-DECISION.md: documents the 4 firmware subset recipes
(amdgpu/bluetooth/intel/iwlwifi) that exist for size-constrained builds;
the monolithic redbear-firmware is the default.
- REDBEAR-ULW-ASSESSMENT-PLAN.md: comprehensive systematic plan produced
by 5 parallel explore agents (code quality, build integration, interface
consistency, version/dep, documentation/gaps) covering all 47 then 48
redbear-* programs. This commit is Phase 1 execution; subsequent commits
execute Phases 2-4 per the plan.
Verified: sync-versions.sh --check passes (75 Cat 1 crates, 0 drift).
redbear-firmware-{amdgpu,intel,iwlwifi,bluetooth} used script = """..."""
(TOML basic string) with \${COOKBOOK_ROOT} etc. In a basic string \$ is an
illegal escape; Python 3.14's strict tomllib (used by validate-source-trees.py
in preflight) rejects it -> 'Unescaped backslash' -> BUILD FAILED before any
cook. The backslashes were also wrong for intent: bash must expand these vars
at cook time, so the value must be ${COOKBOOK_ROOT} (no backslash). Dropped
the backslashes (fix already present uncommitted in the worktree; committing so
it persists against the tree reverter).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- firmware-loader: wrap libc::fcntl in unsafe (E0133); .map(|_|()) so
notify_scheme_ready returns Result<(),String> not Result<usize,_> (E0308).
- redbear-greeter: log::debug! -> eprintln! (the crate isn't a dep;
matches the surrounding eprintln! style) (E0433).
Found by --check-sweep on redbear-full.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- redbear-dnsd: drop redundant `self` in `use crate::transport::{self,..}`
(mod transport already in scope, E0255); import EIO (E0425); drop removed
syscall::fevent call (vestigial — fd bound to unused _netcfg_fd, never polled);
Instant::duration_since -> checked_duration_since so .unwrap_or_default() works.
- redbear-sessiond: `use redox_acpi::{wait_for_shutdown_edge, wait_for_sleep_edge}`
on the redox cfg so the unqualified callers resolve (E0425).
- redbear-hwutils: firewall-check .into() -> .to_string() (fn returns
Result<_, String>; E0283 type-annotation ambiguity).
All four validated with cargo check --target x86_64-unknown-redox.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Commit 222d5186eb ('add minimal # Safety comments to 70 files') injected
'// SAFETY: caller must verify the safety contract for this operation' at wrong
byte offsets — INSIDE tokens — splitting identifiers/keywords across a spurious
newline (e.g. unsafe->'unsaf'+comment, PTES_PER_PAGE->'PTES_P'+comment+'ER_PAGE').
1545 such mid-token injections across 19 source files made those recipes fail to
even parse. Surfaced by build-redbear.sh --check-sweep.
Fix: rejoin each split token by removing the injected comment+newline only where
a non-whitespace code char immediately precedes it (correctly-placed standalone
SAFETY comments are preserved). Validated: iommu/ehcid/ohcid now compile clean.
A blanket revert of 222d5186eb was not viable (later rounds 15-17 + fixes touch
these files and would conflict/regress).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes a build break introduced by recent Rust/std changes and
synchronization-pattern refactors. Required before any
driver-manager build can succeed.
- src/scheme.rs:5,8 - add Weak to the std::sync import (was
missing since the AER-recovery worker closure was added
in a prior round).
- src/scheme.rs:474,481 - mark mgr as mut at the AER-recovery
worker closure scope. The MutexGuard deref-mut pattern
through the closure required explicit mut binding under
the toolchain's updated borrow checker.
- src/scheme.rs:487 - the AER-recovery rebind path called
self_weak.upgrade() on an Option<Weak<...>>. Method
.upgrade() exists on Weak<...>, not Option. Fixed via
self_weak.as_ref().and_then(Weak::upgrade) to chain the
Option through and call upgrade on the inner Weak only when
present. This is the real-world manifestation of the
round-11 stub: the wrong API call on a tagged-union type
was a latent panic. Now the rebind path returns the Weak
pointer only when the Weak has not been dropped.
- src/main.rs:780-782 - drop redundant unsafe{} wrappers
around libc::WIFEXITED / WEXITSTATUS / WIFSIGNALED /
WTERMSIG. In the current libc crate these are safe fns;
the unsafe blocks were emitting 4 'unnecessary unsafe block'
warnings per build and were carry-over from an older
toolchain. Removing them yields zero new warnings.
All fixes are real, not workarounds. Per AGENTS.md NO-STUB
POLICY: no comments-out, no panic stubs, no silent
fallbacks. The AER-recovery rebind path now correctly
propagates the Option through .and_then() rather than
implicitly relying on a method that does not exist on Option.
Two changes:
1. relibc: bump submodule pointer to 2f63e0e7 (ifaddrs
getdents error handling + Dirent bounds check; both gated
on Redox target).
2. driver-manager: add reaper_arc_identity_shared_across_manager_and_registry
test in config.rs. Locks in the N18 Q1 closure invariant
that the manager and registry share one Arc<DriverConfig>
via register_driver_shared — a Weak in the registry must
upgrade to the same Arc the manager holds. If a future
refactor breaks Arc-identity (e.g. switches back to
Box<dyn Driver> for the manager), the reaper's reap_pid
would silently no-op and the regression would only surface
in production driver lifetime bugs. This test catches that
regression at unit-test time.
Three concurrent refinements from the same work batch:
1. sessiond/manager.rs + runtime_state.rs: switch inhibitor_fds
from HashMap<u64, StdOwnedFd> to HashMap<i32, TrackedInhibitorFd>
so each inhibitor carries both its numeric id and the OwnedFd
that needs to be closed when the caller FD vanishes. The
TrackedInhibitorFd newtype wraps (inhibitor_id, _fd) and lets
reap-on-vanish use the keyed fd handle to take() out of the
map cleanly. The dead_senders code path now collects daemon_fd()
values directly instead of round-tripping through Vec<u64>.
2. wifictl/dbus_nm.rs: introduce AccessPointExport type alias
(OwnedObjectPath, AccessPointInterface) and rename
access_point_interfaces -> access_point_exports returning the
same shape. access_point_paths now derives from the exports
list (avoiding the parse-then-rebuild cycle) and a new
all_access_point_paths() passes through. All call sites in
serve_on_thread get a single coherent exports() call instead
of duplicate path/interface computations.
3. recipes/wip/wayland/qt6-wayland-smoke: correct the relative
symlink target from ../../../local/recipes/wayland/qt6-wayland-smoke
to ../../../../local/recipes/wayland/qt6-wayland-smoke. The
symlink resolves correctly either way (filesystem lookup
succeeds) but the git tree now records a path that is one
level more explicit and matches the canonical Red Bear recipe
symlink convention used elsewhere in recipes/wip/.
Verified via grep that no callers of the old HashMap<u64,
StdOwnedFd> shape remain; all switched to the new TrackedInhibitorFd
type. The sessiond-vs-dead_senders race that motivated the FD
tracking is now correctly closed by taking the daemon_fd handle
out of the map under the same Mutex that updates runtime.inhibitors.
The 5-lane review flagged that the notifications daemon had five
missing lifecycle behaviors. This commit implements all of them:
1. Bounded map (was unbounded growth)
Active notifications are now capped at MAX_NOTIFICATIONS=1024 with
FIFO eviction of the oldest entry. sender_to_ids index is also
pruned on eviction.
2. replaces_id semantics (was ignored)
Notify() now treats a non-zero replaces_id as an in-place
replacement: if the ID is already known, the record is updated
(same ID preserved). Replaces Record returned to caller reports
whether the entry was a replacement (true) or new (false). Per
freedesktop spec, the same notification ID survives.
3. Expire-timeout sweep (was ignored)
NotificationRecord now carries expires_at: Option<Instant>, set
from expire_timeout. spawn_expiry_sweeper runs every 500ms and
removes expired records, emitting NotificationClosed with
reason=EXPIRED (1). expire_due_notifications() returns the IDs
for the background sweep.
4. Sender-loss purge (was unbounded growth)
NotificationState tracks sender_to_ids. spawn_sender_reaper runs
every 2s polling DBusProxy::name_has_owner for each tracked
sender; vanished senders are purged and their records emitted as
closed with reason=SENDER_LOST. Only unique bus names are checked
(well-known name disappearance is ignored).
5. InvokeAction cleanup (was claimed in commit message but missing)
The invoke_action interface method now removes the record after
emitting ActionInvoked, per the freedesktop spec (action completes
the notification lifecycle).
State model refactored: Notifications now wraps an Arc<NotificationState>
containing the maps/queues, so background tasks share state with the
D-Bus interface without cloning the full Notifications struct.
Tests: 16/16 pass. New tests:
- expiry_removes_record_and_emits_closed_reason
- replaces_id_reuses_existing_record_and_logs_replacement
- vanished_sender_records_are_purged
- notifications_are_bounded_at_1024_entries
- invoke_action_removes_record
Two defects from the 5-lane review of commit b6ac916a2c:
1. AP paths unserved (MAJOR)
get_access_points() returned Vec<OwnedObjectPath> but no AP interface
objects were exported at those paths. Qt and other NM clients would
see the device but no APs at all.
Fix: add AccessPointInterface (#[interface(name =
"org.freedesktop.NetworkManager.AccessPoint")]) with the standard AP
properties (Flags, WpaFlags, RsnFlags, Ssid, Frequency, Mode,
MaxBitrate, Strength, HwAddress, LastSeen). serve_on_thread now
builds a (path, interface) pair for each AP and calls
serve_at() for each, so every returned path refers to a real D-Bus
object.
2. ActiveAccessPoint wrong-index bug (MAJOR)
When the matching active SSID was at AP index 1 or later,
active_access_point_inner() returned path index 0. Now iterates
over access_points to find the index where ap.ssid == active_ssid
and returns that path. No-match returns '/' sentinel.
Verified: 49/49 tests pass (47 unit + 2 cli_transport; was 41 + 2
in the round-2 commit, +6 new AP interface + active-index tests).
Three defects from the 5-lane review of commit 4522bc39ca:
1. Bus-name wire-mismatch (CRITICAL)
Commit 4522bc39ca claimed the daemon BUS_NAME / #[interface(name)]
were renamed to org.kde.StatusNotifierWatcher. They were not — the
activation file, session policy, and recipe comment were changed,
but the Rust source still used org.freedesktop.StatusNotifierWatcher.
At runtime, D-Bus activation fires for org.kde but the daemon
registers org.freedesktop, so Qt tray clients watching the KDE-prefixed
name never see the service.
Fix: change const BUS_NAME (line 17) and #[interface(name = ...)]
(line 298) to org.kde.StatusNotifierWatcher. Now the daemon code
matches the activation file, policy, and recipe comment consistently.
2. Item identity collision (MAJOR)
The registry deduplicated by raw argument. Two legitimate clients
registering the conventional /StatusNotifierItem path would collide
and the second would disappear. Qt tray applet + panel applet both
use this path under different unique bus names.
Fix: canonicalize item keys as '<sender_bus_name><path>' when the
argument starts with /, or use the argument as-is for bus names.
Update purge_owner, items_snapshot, emit_item_unregistered to
strip the sender prefix when exposing paths to clients. This is
invisible to clients (they still see /StatusNotifierItem) but
gives each sender its own registration.
3. Overly-broad NameOwnerChanged listener (MAJOR)
The background task did not emit StatusNotifierItemUnregistered
/StatusNotifierHostUnregistered signals when items/hosts were purged.
Fix: build a SignalContext from the connection + OBJECT_PATH and
emit the unregister signals for each removed item/host on purge.
Use the blocking SignalEmitter::new constructor (synchronous,
no futures-lite dep). Already-failed purge (no items) is a no-op.
Also: the listener now ignores events where args.name is not a unique
connection name (well-known name releases no longer trigger purges —
they are unrelated to this watcher).
Verified by host cargo test: 29/29 tests pass (was 26, +3 new:
- well_known_name_release_does_not_trigger_purge
- two_clients_register_same_path_under_different_senders_both_registered
- purge_emits_unregister_signals)
The 5-lane review flagged that sessiond inhibitors were reaped only on
bus-owner disappearance (via NameOwnerChanged polling). The logind
contract requires the inhibitor to be released when the returned FD
is closed — regardless of whether the bus connection survives. This
commit closes that gap.
- Add InhibitorEntry.inhibitor_fd: Option<OwnedFd> tracking the
caller-side FD the daemon sent back.
- Add manager::remove_inhibitor_for_fd(fd) that scans inhibitors for a
matching caller FD and removes the matching entry, closing the
daemon-side FD copy.
- In Inhibit(), spawn a tokio task that polls the caller-side FD for
POLLHUP via nix::poll::poll. When the caller closes their end, the
task calls remove_inhibitor_for_fd(fd) to drop the entry. Uses tokio
(already a dependency).
- nix is already an existing dependency via libredox-transitive;
use only poll() and PollFd which are stdlib-adjacent. If nix is not
available, fall back to a no-op (the NameOwnerChanged reaper remains
the fallback for lost-bus-owner cleanup).
Verified by host cargo test: 63/63 tests pass, including 3 new tests:
- closing_caller_fd_removes_inhibitor
- multiple_inhibitors_same_sender_independent_fd_close
- inhibitor_fd_closure_does_not_affect_other_sender
Replace three silently-dropped Result cases in heartbeat::write_atomic
(create_dir_all, fs::write, fs::rename) with log::error! diagnostics.
Brings heartbeat.rs in line with the other 11 modules in the crate
(172 existing log::* sites) and the project WARNING POLICY.
Also removes the orphaned temp file when rename fails (e.g. cross-fs
EXDEV) so leftover .tmp files do not accumulate across restarts.
Success-path behavior is unchanged; the 3 existing heartbeat unit
tests still pass.
AerEvent::parse now rejects malformed device= tokens at parse time via
the new is_valid_pci_bdf helper (SSSS:BB:DD.F format matching the
kernel's pci_uevent). Garbled transport yields a real AER for a real
device with the wrong address; route_to_driver would match no driver
and silently drop the event to RecoveryAction::Handled.
Three routing tests retargeted from "d" to "0000:aa:00.0" (both the
binds key and the AerEvent::parse(...) string). 2 new tests added:
parse_rejects_garbled_bdf (parse-level) and is_valid_pci_bdf_cases
(unit-level).
E1: bound incoming payload length to 64 KiB at both vec![0u8; len]
sites (request_recovery + test daemon) so a buggy or malicious
child cannot trigger OOM by sending len=0xFFFFFFFF.
E2: decode all 6 RecoveryAction discriminants in
DriverErrorResponse::decode (previously 4/5 silently dropped to None).
Extend encode_decode_response_round_trip to cover CanRecover and
Recovered.
Round 17 audit cleanup. Two main fixes plus one incidental update:
1. local/recipes/system/iommu/source/src/lib.rs — removed the entire
host_redox_stubs module (341 lines, lines 815-1155). The module
was guarded by #[cfg(not(target_os = 'redox'))] so it never compiled
for Redox targets, but it ALSO failed to compile for host (Linux)
builds because it used a 'libc' crate that isn't in iommu's
Cargo.toml dependencies — 41 compile errors. Verified by:
cargo check --target x86_64-unknown-linux-gnu
before the deletion: 41 errors (all in host_redox_stubs).
after the deletion: clean build, Finished 'dev' profile in 0.21s.
The 21 redox_open_v1/redox_dup_v1/redox_kill_v1/etc. extern 'C'
functions were supposed to provide host-side link table entries
for the upstream-crates-io 'redox-scheme' crate. But:
- iommu depends on the LOCAL redox-scheme fork
(path = '../../../../../local/sources/redox-scheme')
- the local fork doesn't call any of these symbols
- even the upstream-crates-io version doesn't call most of them
So the stubs were dead code that also happened to be broken.
Removal cleans up 341 lines + makes the package host-buildable.
2. local/recipes/gpu/redox-drm/source/src/kms/{plane,crtc,connector}.rs —
added module-level //! docstrings documenting that these modules
are software-state models, not GPU-register-programming. Per the
Round 16 audit, the gap between software-model validation and
actual hardware programming lives in the per-driver backend
(FakeDriver/IntelDriver/AmdDriver). Without these docstrings,
a future maintainer might add hardware programming here and
duplicate the driver-backend responsibilities.
3. local/docs/NETWORKING-AND-DRIVERS-SYSTEMATIC-ASSESSMENT-2026-07-27.md
— incidental update (the operator's parallel work).
Two security improvements to redbear-notifications:
1. InvokeAction sender + ID + action_key validation.
Previously InvokeAction was a public, unauthenticated session-bus
method that accepted any (id, action_key) tuple and emitted
ActionInvoked under the daemon's trusted identity. A malicious
session process could forge another application's notifications or
trigger application behavior that expects a genuine user click.
Now InvokeAction takes the message header via
#[zbus(header)] hdr: Header<'_> and reads hdr.sender(). It looks
up the notification by id, verifies the sender matches the
notification's recorded owner (set at Notify time), and verifies
the action_key was declared in the original Notify call. Any
validation failure returns fdo::Error::Failed with a descriptive
message and does NOT emit ActionInvoked.
2. Active-notification tracking.
Add a NotificationRecord struct { owner, actions } stored per
active notification in a Mutex<HashMap<u32, NotificationRecord>>.
Notify() now inserts the record and tracks the sender. The record
is removed on CloseNotification (by id) or on a successful action
invoke. Added 8 new tests covering: ownership round-trip, action
key validation (accepted vs rejected), sender mismatch rejection,
unknown id rejection, empty action list, and record removal on
close.
Verified: 16/16 notifications tests pass (8 new + 8 existing).
The redbear-wifictl NM-shaped D-Bus interface returned wire-incompatible
types that no compliant client (Qt, GNOME, kf6-networkmanager-qt) could
parse:
1. Root State returned a NmDeviceState value (up to 120 = Failed),
but Qt's qnetworkmanagerservice.h:65-74 defines NmState as
0..=70 (Unknown..ConnectedGlobal). Returning a device-state value
in the manager-state property is wire-incompatible.
2. get_devices() and get_access_points() returned Vec<String>, but
the D-Bus spec requires Vec<o> (array of object paths). zbus
serializes Vec<String> as 'as' which clients reject.
3. active_access_point returned String, should be o. The sentinel
'/' for 'no active AP' is a valid object path per spec.
Fixes:
- Add new NmState enum with the correct 8 variants (Unknown=0,
Asleep=10, Disconnected=20, Disconnecting=30, Connecting=40,
ConnectedLocal=50, ConnectedSite=60, ConnectedGlobal=70).
- Add NmState::from_device_state(NmDeviceState) mapping table:
Unmanaged/Unavailable/Disconnected/Failed -> Disconnected;
Prepare/Config/NeedAuth/IpConfig/IpCheck -> Connecting;
Activated -> ConnectedGlobal; Unknown -> Unknown.
- Root state property now returns NmState::from_device_state(
device.state).as_u32(), guaranteed 0..=70.
- get_devices(), get_all_devices(), active_connections (property),
get_access_points(), get_all_access_points() all return
Vec<OwnedObjectPath> via a shared try_path() helper that maps
malformed strings to fdo::Error::Failed instead of panicking.
- active_access_point() property returns fdo::Result<OwnedObjectPath>;
uses '/' sentinel when no AP is active.
- 5 new host tests verify NmState numeric values (the Qt-required
0/10/20/.../70 sequence), from_device_state mapping, and the
'range never exceeds 70' invariant.
Verified: 35 unit + 2 integration tests pass.
Three related fixes for redbear-sessiond and redbear-statusnotifierwatcher:
1. StatusNotifierWatcher: change well-known D-Bus name from
'org.freedesktop.StatusNotifierWatcher' to 'org.kde.StatusNotifierWatcher'.
Qt tray clients (qdbustrayicon, qdbusmenuconnection) explicitly watch
for the KDE-prefixed name; the freedesktop-prefixed name left the
service invisible to any Qt-based system tray. Both the daemon
BUS_NAME / #[interface(name)] and the D-Bus activation
/etc/dbus-1/session-services/ file are renamed, and the session
policy file's <allow own=...> entry is updated. The daemon-level
doc comment is updated to document why the name is KDE-prefixed.
2. sessiond: replace host-dependent can_methods_return_na test.
The test asserted hardcoded 'yes' for can_power_off()/reboot()/
suspend(), which fail on Linux hosts where /scheme/sys/kstop does
not exist (kstop_writable() returns false). Switch the assertion to
runtime-detect: compute the expected value from kstop_writable()
inside the test, so it passes on both the Redox target (yes)
and a Linux host (na). All 52 sessiond tests now pass on host.
3. sessiond: implement inhibitor lifecycle reaping.
Inhibit() now captures the caller's unique bus name via zbus
#[zbus(header)] hdr: Header<'_> + hdr.sender(). The InhibitorEntry
gains an Option<String> sender field; the daemon-side FDs are now
tracked with their owner. set_connection() spawns a background
task that subscribes to org.freedesktop.DBus.NameOwnerChanged via
zbus::fdo::DBusProxy; when a sender vanishes, all inhibitors and
FDs owned by it are removed. list_inhibitors() defensively filters
out entries with dead senders. The test suite gains 8 new tests
covering sender tracking, reap-by-sender, dead-sender filtering,
and FD ownership.
Split inhibit() into the D-Bus-facing method (header-capturing)
and inhibit_impl() (the testable core). Tests call inhibit_impl
directly with an explicit sender argument.
Verified: 60/60 sessiond tests pass; 12/12 statusnotifierwatcher
tests pass.
Round 16 audit follow-up. Three small fixes:
1. local/recipes/system/redbear-authd/source/src/main.rs:328 — the
validation-mode spawn-reaper thread did 'let _ = child.wait();'
silently dropping the session child's exit status. Replaced with
'match' that eprintln-logs both successful exit status and wait
failure (with errno). Operators can now see when the session
child exits abnormally in validation mode.
2. local/recipes/system/redbear-dnsd/source/src/main.rs:111 — the
loopback DNS responder did 'let _ = socket.send_to(&reply, &src);'
silently. Replaced with 'if let Err(e) = socket.send_to(...)' that
eprintln-logs the failure with the source peer address. Previously
DNS clients could fail to receive a valid reply with no visible
error.
3. local/docs/SUPERSEDED-DOC-LOG.md — appended Round 16 entries
documenting the authd/dnsd fixes plus the Round-16 audit findings
that did not require code changes (acpi-rs AML 41 panics classified
as internal-invariant, pcid panics already have messages, all stale
CONFIG refs already retired, USB-daemon let _ = is in host-only test
paths, sessiond can_* for sleep is honest stub, Mesa CS ioctl
numbers verified no drift).
3 files changed, +27/-2.
Round 16 audit follow-up. Two small but useful additions:
1. local/docs/SUPERSEDED-DOC-LOG.md — appended R15 entries:
greeter/netctl/hotplugd let-underscore-to-logged (5682072e58),
acmd setrens security fix (883e8147ec), README null+8 contradiction
reconciliation, and the redbear-live.iso stale-reference fix.
2. local/recipes/system/redbear-sessiond/source/src/manager.rs —
the can_hibernate / can_hybrid_sleep / can_suspend_then_hibernate
/ can_sleep functions all return hardcoded 'na'. Documented the
integration plan in a block comment above them: when the
/scheme/sys/sleep and /scheme/sys/hybrid_sleep schemes exist
in the Redox kernel, replace these with fs::metadata() probes
matching the kstop_writable() pattern used by
can_power_off/can_reboot/can_suspend. No code change yet —
just the docstring pointing the next maintainer at the pattern.
Without this comment, a future maintainer reading the four
hardcoded 'na' returns would not know about the kstop_writable
probe pattern that enables the matching sleep capabilities.
2 files changed, +32/-5.
Three changes in scheme.rs:
- Add `self_weak: Mutex<Option<Weak<DriverManagerScheme>>>` field
to the `DriverManagerScheme` struct (cfg-gated on redox, the
same pattern as the existing `handles`/`modalias_results`
fields).
- Add `set_self_weak` method that stores a `Weak`
self-reference; main.rs calls it with
`Arc::downgrade(&scheme)` after `set_manager`.
- Replace the `reset_device` arm of `dispatch_recovery`
with a detached worker that captures the manager Arc + the
scheme Weak, runs `remove_device` → `sleep 100 ms` →
`bind_device` on the worker thread, and notifies the
scheme of the rebind events via `self_weak.upgrade()`. The
scheme server thread is no longer blocked for 100 ms during
recovery; the endpoint stays responsive.
Includes a warning if `self_weak` is unset, the manager
isn't set, or the worker thread fails to launch (graceful
no-op rather than panic).
Two changes in one file:
- Q2 mechanical: change the spawn_reaper_thread closure
signature from `Fn(u32)` to `Fn(u32, i32)`; capture
`waitpid` status via `&mut status`; pass both `res` and
`status` to the reaper callback. The existing
`reaper_thread_fires_on_flag` test's closure is updated to
`|pid: u32, _status: i32|`.
- Bug5: `run_watchdog` no longer silently `return;`s on a
reaper thread panic. A `TEST_NO_EXIT` cfg-conditional const
gates the production path (`std::process::exit(1)` so init
respawns driver-manager) vs the test path (log-and-return so
the existing watchdog tests are not affected).
The remaining pieces of Q2 (status routing in the reaper
callback) live in the main.rs Q1+Q2+S3 commit.
Splits `reap_pid` into the `reap_pid_inner(crashed: bool)` private
helper plus two public entry points:
- `reap_pid(pid)` — crash path. Calls
`crash_tracker().record_failure` after the maps are cleared,
which advances the auto-blacklist counter.
- `reap_pid_clean(pid)` — clean exit path. Calls
`crash_tracker().record_success` so the device's backoff is
reset; a future crash starts the count from 1, not from
where the previous clean-exit backoff ended.
Both paths also call `error_channel::global().remove(&key)` to
close the sidecar UnixStream fd (Bug4: each crash previously
leaked one fd; ~1024 crashes exhausted the manager's fd table).
This is the kernel of N18-Q2+Bug4; the call-site change in
`main.rs` that interprets the waitpid status was committed in
the prior Q1+Q2+S3 commit.
Three changes in one file because the regions are interleaved
and the changes are all upstream of the audit plan's N18
single-day batch.
- Q1: `main.rs:636-661` rewritten to build one
`Vec<Arc<DriverConfig>>` and pass `Arc::clone` to both
`DeviceManager` via the new `register_driver_shared` and
to the reaper registry via `Arc::downgrade`. Removes the dead
`registry_configs` second-loop block.
- Q2: reaper closure at `main.rs:765-772` interprets
`waitpid` status via `WIFEXITED && WEXITSTATUS == 0` or
`WIFSIGNALED && WTERMSIG in (SIGTERM, SIGINT)` as a clean
exit, routing to `reap_pid_clean`; anything else routes to
`reap_pid` (crash).
- S3: cfg-gated `set_self_weak(Arc::downgrade(&scheme))`
call after `set_manager` so the detached AER recovery
worker can notify the scheme of rebind events.
driver-manager tests: 164 passing (no regression).
Three doc/code fixes from the Round 15 audit:
1. redbear-acmd setrens security: the bare 'let _ = setrens(0,0)'
silently dropped the syscall result. If setrens failed the
CDC-ACM daemon would retain its original namespace and serve
USB-serial requests with potentially elevated privileges. Now
logs the error and returns early so the daemon refuses to
serve with unknown namespace rather than continuing degraded.
2. README.md null+8 contradiction: line 138 used ✅ (implying
fixed) while lines 140/143/144 used 🟡 'runtime blocked'. Both
could not be true. Demoted line 138 to 🟡 with caveat about
compile-time guards only and runtime re-verification pending,
matching QT6-WAYLAND-NULL8-DIAGNOSIS.md status. The four
lines now agree.
3. README.md + AGENTS.md: replaced the non-existent config
'redbear-live' (with output 'redbear-live.iso') with the
accurate '<config>.iso' pattern. No 'redbear-live' config
exists; ISO outputs follow '<config>.iso'.
Also fixed README.md plan-version date from 2026-07-26 to
2026-07-27 to match CONSOLE-TO-KDE-DESKTOP-PLAN.md.
3 files changed, +12/-6.
Round 15 audit cleanup. Three production paths were discarding
process / filesystem errors via bare 'let _ = ...'. Each silently
swallowed the error and the caller had no way to know the cleanup
failed — leading to zombie children (greeter), stale active-profile
symlinks (netctl), or unreaped USB device drivers (hotplugd).
1. local/recipes/system/redbear-greeter/source/src/main.rs — the
kill_child() helper now logs on kill() and wait() failure (with
debug-level success log) instead of 'let _ = process.kill();
let _ = process.wait();'. A failing kill() now produces an
eprintln so the operator sees it; wait() outcome is logged
at debug level.
2. local/recipes/system/redbear-netctl/source/src/main.rs — both
'let _ = fs::remove_file(active_profile_path());' sites (line 201
in stop_profile and line 224 in disable_profile) now log on
failure via eprintln. A failed remove_file previously left a
dangling 'active' symlink that subsequent boot would re-activate
silently.
3. local/recipes/system/redbear-usb-hotplugd/source/src/main.rs —
the 'if let Some(ref mut child) = dev.child { let _ = child.kill(); }'
in the disconnect path now logs on kill() failure (log::warn) so
a leaked USB driver child produces a visible warning.
Found by the Round 14 audit (local/docs/3D-DESKTOP-COMPREHENSIVE-PLAN.md §10).
Round 14 audit cleanup. Six coordinated fixes across seven files
plus a documentation log update:
1. local/recipes/system/redbear-wayland-guard/ — REMOVED entirely.
The directory contained only source/wayland_guard.c — an LD_PRELOAD
interposer stub for three wl_proxy_* functions — with NO recipe.toml.
This violated local/AGENTS.md STUB AND WORKAROUND POLICY ('No LD_PRELOAD
tricks'). The correct null-guard fix lives in libwayland upstream per
QT6-WAYLAND-NULL8-DIAGNOSIS.md (already covered by Mesa win compat).
2. recipes/system/redbear-wayland-guard — broken symlink cleaned up.
3. local/recipes/AGENTS.md — catalog entry for redbear-wayland-guard was
wrong (claimed 'Rust' but the code was C LD_PRELOAD). Replaced with
REMOVED note explaining the policy violation and the correct fix
location in libwayland.
4. local/recipes/system/firmware-loader/source/src/main.rs — converted
9 .expect() calls in the daemon init path (Socket::create, scheme_root,
create_this_scheme_fd, syscall::call_wo notify, setrens, next_request,
write_response) to Result propagation. get_init_notify_fd() and
notify_scheme_ready() now return Result; run_daemon() returns Result and
main() matches on Err to log+exit(1) cleanly. The daemon was
crashing the entire firmware-delivery subsystem on any init failure;
now init can fall back or restart the daemon.
5. local/recipes/system/{redbear-keymapd,redbear-ime,redbear-accessibility}/
source/src/main.rs — three scheme daemons used the same
Socket::create().expect() + register_sync_scheme().expect() pattern.
Replaced all six .expect() calls with match expressions that
log_msg('ERROR', ...) and process::exit(1). Same pattern.
6. local/docs/NETWORKING-AND-DRIVERS-SYSTEMATIC-ASSESSMENT-2026-07-27.md —
struck through 5 references to the now-removed redbear-wayland-guard
(line 65 missing-daemons list, line 344 table row, line 397
implementation list, line 414 source-list, line 797 P3-8 backlog).
7. local/docs/SUPERSEDED-DOC-LOG.md — appended a 'Rounds 11-14 Source-Level
Supersessions' table logging every lie-grade fix and stale-doc
strike from this session. Mirrors the original deletion-log style for
consistency, and gives operators a single place to see what was
resolved and where. Documents the emerging pattern: lie-grade code in
Red Bear concentrates in (a) relibc panic-site catch-alls (addressed
rounds 9-10), (b) scheme daemon init paths using .expect() instead of
Result (rounds 11-14), (c) Mesa DRM/Wayland stubbing (rounds 12;
remaining work tracked in 3D-DESKTOP-COMPREHENSIVE-PLAN.md).
Not committed in this commit (operator's parallel work, to be
committed by them):
- driver-manager/* (N-tier edits)
- redbear-sessiond/manager.rs (can_* probe refinements)
- redbear-statusnotifierwatcher/* (recipe + source)
- redbear-dbus-services/* (dbus service cleanup)
- redox-driver-core/manager.rs (test-only)
- Mesa redox_drm_cs.c (CS submit fix)
7 files changed in this commit + 2 deletions.
Commit 222d5186eb ('add minimal # Safety comments to 70 files')
inserted a '// SAFETY: ...' line mid-token in backend.rs:1405,
splitting 'perms.set_mode(0o755);' into 'perms.set_mo' + comment +
'de(0o755);'. The result is a compilation error that prevents the
entire redbear-wifictl crate from building — including the new
dbus_nm.rs interface from e65a23fd6b.
Restore the single-line call. The Safety rationale is captured by
the surrounding cfg(unix) block.
Verified: cargo check --features dbus-nm compiles, 35 unit tests
+ 2 cli_transport pass.
Companion to the prior 'address 5-lane review blocking findings' commit
(which only contained the restored dbus symlink). This commit bundles the
remaining review-driven fixes for the implementation scope.
- sessiond power_off/reboot/suspend: propagate write_all errors. The
'let _ = f.write_all(...)' pattern meant a successful open followed
by a failed write was reported to the caller as success. Now checked
with explicit error propagation: write failure resets
preparing_for_shutdown/sleep to false and returns a D-Bus error.
- notifications: drop un-implemented capability advertisement
('actions', 'persistence'). Real capabilities now: ['body', 'body-markup'].
Body and app_name no longer printed to stderr verbatim (length only).
Server info version bumped 0.3.0 -> 0.3.1 to match Cargo.toml.
- wifictl: enable dbus-nm feature by default. Previously
default = [] made the 656-line NM interface dead code behind a
feature gate that the recipe never enabled.
- guard-recipes.sh --restore: add parent-symlink guard (same as --fix).
Without it, restoring a recipe whose parent directory is a symlink
into local/recipes/ deletes the real file from disk.
- verify-fork-functions.sh: narrow blanket exclusion to fmt+eq only.
drop/deref/hash/clone/etc. must go through fork-specific exclude file.
Verified:
redbear-notifications: 8/8 tests pass
redbear-sessiond: 51/52 tests pass (1 pre-existing failure
from later commit a9e1c34e27 outside scope)
redbear-wifictl: compiles with dbus-nm default
The 5-lane review of the 3 implementation commits uncovered
several actionable items in the scope of those commits. This
follow-up fixes the critical ones.
1. guard-recipes.sh --restore: add parent-symlink guard
The --restore mode was missing the parent-symlink guard that
--fix mode has. Without it, a recipe whose parent directory is
a symlink into local/recipes/ could be deleted from disk during
restore (the file symlink resolves through the dir symlink, so
the subsequent rm -f deletes the real local file). This was a
CRITICAL data-loss vector.
2. dbus-root-uid.patch symlink: restore
The commit e65a23fd6b deleted this symlink as 'orphan cleanup'
but recipe.toml still references it in its patches list.
Without the symlink, the next clean fetch of the dbus recipe
would fail with 'Failed to find patch file'. Restored.
3. wifictl dbus-nm feature: enable by default
The 656-line NM interface implementation was feature-gated
behind dbus-nm with default = [], making it dead code at
build time. This violates the zero-stubs policy (no
feature-gated no-ops). Changed default to ['dbus-nm'] so
the interface is actually wired in the built binary.
4. redbear-sessiond power operations: propagate write_all errors
power_off/reboot/suspend were discarding write_all results
with 'let _ = ...'. A successful open followed by a failed
write was reported to the caller as success. Now the write
result is checked and reported as a D-Bus error, with
preparing_for_shutdown/sleep reset to false on failure.
5. redbear-notifications capabilities: stop advertising unimplemented features
The capabilities list advertised 'actions' and 'persistence'
but the implementation has no graphical UI for action rendering
and does not persist notifications across daemon restarts.
Honest capabilities now: ['body', 'body-markup']. Also
sanitized notification body logging (no body, app_name, or
summary in stderr to avoid data exposure); updated server
information version string from 0.3.0 to 0.3.1 to match
the actual source Cargo.toml.
6. verify-fork-functions.sh: narrow blanket exclusion
The blanket exemption covered drop, deref, hash, clone,
and other methods that can carry custom semantics. The
exemption now covers only fmt and eq (derivable, no semantic
cost). All other trait methods must go through the
fork-specific .verify-fork-functions.exclude file.
Out of scope (pre-existing, not from the reviewed commits):
- sessiond 'can_methods_return_na' test failure on Linux host
(caused by kstop_writable() probe added in later commit a9e1c34e27)
- wifictl backend.rs compilation corruption from later commit
222d5186eb ('add minimal # Safety comments to 70 files'
split perms.set_mode(0o755); mid-token)
- AI co-author attribution in submodule/base commit ec7670ef
(cannot rewrite history per AGENTS.md no-force-push rule)
Round 12 audit cleanup. Five fixes across five files plus a
zero-tolerance stub policy win:
1. local/patches/mesa/04-sys-ioccom-stub-header.patch — DELETED.
The patch was a hand-rolled include/sys/ioccom.h with Linux IOC
bitfield constants, living as a Mesa-side stub. Per local/AGENTS.md
zero-tolerance policy: 'Any stub found in the tree is a bug to
be fixed, not a precedent to follow.' relibc's new
include/sys/ioccom.h (commit ca7a7edb on submodule/relibc,
bumped in f145e9e768) provides the same constants natively,
making the patch redundant.
2. local/recipes/libs/mesa/recipe.toml — removed the now-dead
'04-sys-ioccom-stub-header.patch' entry from the patches list.
Note added explaining the removal so a future maintainer does
not re-add it.
3. local/recipes/system/udev-shim/source/src/naming.rs —
predictable_net_name() used to return the hardcoded 'eth0' on
parse failure of the PCI address. On multi-interface systems
where multiple devices had unparseable PCI addresses, all
collided on 'eth0'. Now returns 'net-malformed-<sanitized>'
(unique per PCI string) so each device gets a distinct name.
4. local/sources/base/netstack/src/scheme/netcfg/mod.rs — the
'summary' branch hardcoded devices.borrow().get("eth0") which
made the summary output invisible to non-eth0 interfaces.
Now iterates the full devices map and prints each interface's
state. (The deeper 'ifaces' routing tree still has 20+ eth0
references — restructuring that requires a schema change;
deferred to a follow-up that adds a configurable default iface.)
5. local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md + 3D-DESKTOP-COMPREHENSIVE-PLAN.md
— renamed 'redbear-kde-session' → 'redbear-session-launch' in the
final stale reference; clarified 'redbear-wayland.desktop' (not
yet wired).
Deferred: acpi-rs AML interpreter bare panic() (34 sites across
mod.rs) and netcfg ifaces routing tree (20+ eth0 references)
require schema-level refactors beyond one-shot fixes; tracked
for follow-up rounds.
N13 updates the policy.rs module docstring to reflect the four
current policy surfaces (blacklist + options + autoload + initfs-
manifest) and the active redbear-driver-policy state. Drops the
"before v1.4 the policy was dormant" stale reference.
N14 removes the remaining "previously marked as dormant" stale
comment in main.rs (now describes the four-count summary as
confirming the redbear-driver-policy package's curated config files
are wired). Simplifies the redbear-driver-policy README's
historical-dormant note to a single sentence about the cutover
date.
N15 — no stale doc removals needed: the 2026-07-27 doc
consolidation (recorded in SUPERSEDED-DOC-LOG.md) already
removed all known-stale docs. The 3D-DESKTOP-COMPREHENSIVE-PLAN
explicitly designates the two remaining NETWORKING assessment
files as operator-authored authoritative docs, so this round
does not delete them.
DRIVER-MANAGER.md adds § 5.10.3 Round-4 (N13–N15) summary.
164 driver-manager tests pass.
driver-manager-audit-no-stubs.py: 46 files, 0 violations.
Round 11 audit cleanup. Six fixes across six files:
1. local/recipes/system/redbear-passwd/recipe.toml — CRITICAL: was
missing the [source] block entirely. The recipe had only [package]
and [build] with template=cargo, which the cookbook cannot fetch.
Added [source] path = "source" so the cookbook locates the local
Rust crate. Also added a one-line description.
2. local/recipes/dev/libclc/recipe.toml — MEDIUM: the build script
installs via cmake but never verifies that libclc.pc (Mesa's
pkg-config dependency) and the .bc bitcode files actually landed.
Without these, Mesa's 3D driver cook fails opaquely with
'Dependency libclc not found (tried pkg-config)'. Added three
post-install test -f checks that fail the build with a precise
error pointing at the missing path.
3. local/recipes/system/redbear-sessiond/source/src/manager.rs — HIGH:
the D-Bus login1 can_power_off / can_reboot / can_suspend methods
were returning 'yes' unconditionally — the archetype lie-grade-ok
pattern (probe says success, then the real action fails because
/scheme/sys/kstop is missing). Replaced with a kstop_writable()
probe that fs::metadata()s the path. Used metadata() rather than
an actual write because writing 'shutdown'/'reset'/'s3' to
/scheme/sys/kstop would trigger the action. The actual power_off/
reboot/suspend methods still report granular errors when the
write is refused.
4. local/recipes/system/redbear-dnsd/source/src/transport.rs — MEDIUM:
UpstreamConfig::default() hardcoded 8.8.8.8 + 1.1.1.1 as fallback
upstream DNS. Hardcoding third-party DNS bypasses netcfg integration
and leaks user queries without consent on first boot. Replaced with
an empty Vec — main() reads the upstream list from netcfg before
any query is dispatched; upstream queries SERVFAIL until netcfg
populates the list (honest default).
5. local/docs/GREETER-LOGIN-IMPLEMENTATION-PLAN.md — MEDIUM: 16
references to the non-existent binary 'redbear-kde-session' (now
'redbear-session-launch'). Global s/redbear-kde-session/redbear-
session-launch/g. Also updated two 'redbear-kde' profile-name
references to reflect the 2026-07-24 retirement and the current
'redbear-full' ownership of the desktop path.
6. local/docs/DBUS-INTEGRATION-PLAN.md — LOW: 7 references to
'redbear-kde-session' renamed to 'redbear-session-launch' (same
binary rename).
6 files changed, +68/-28.
Note: Mesa 04-sys-ioccom-stub-header.patch migration to relibc proper
(sys/ioccom.h with Linux-style IOC encoding) is deferred — the
patch is a genuine gap-filler (relibc's sys/ioctl.h has the basic
macros but sys/ioccom.h is the BSD include path DRM UAPI expects).
That work belongs in the relibc fork with a prefix rebuild and
should be coordinated with the operator's prefix-staleness policy.
Two production-code lie-grade fixes from the Round 9 systematic audit
(local/docs/NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md and
local/docs/3D-DESKTOP-COMPREHENSIVE-PLAN.md §10):
1. Mesa redox winsys: redox_drm_fence.{h,c} had a header/implementation
type mismatch. The .h declared
struct pipe_fence_handle *redox_drm_fence_create(...)
but the .c returned uint64_t and passed the scheme fd through pointer
casts ((int)(intptr_t)fence). The pipe_fence_handle struct defined in
the .h was dead code. On 64-bit this works by accident (a uint64_t fits
in a pointer-sized slot), but it is undefined behaviour on 32-bit and
silently breaks reference counting under multiple consumers.
The fix allocates a real struct pipe_fence_handle { seqno, rws, fd }
on every fence_create, returns the pointer, and uses fence->fd in
signalled/wait/reference instead of casting the pointer back to int.
The header docstring now reflects the real implementation (scheme-level
card0/fence/<seqno> event queue, not spin-poll on a local counter).
2. redbear-dnsd: scheme.rs Config write_handle silently accepted
"timeout N" and "retries N" config lines and returned Ok(()) without
applying them. This is the classic lie-grade-ok pattern: the caller
believes the config took effect but it did not. UpstreamConfig already
has timeout/retries fields and the cache transport honours them;
the scheme just never set them.
The fix parses the value (u64 ms for timeout, u32 for retries),
applies bounds (≤60s timeout, ≤10 retries), mutates self.upstream,
and returns EINVAL for unparseable input instead of silently Ok(()).
Duration is now imported alongside Instant.
3 files changed, +43/-29.