The relibc-consumer invalidation (correctly) force-deletes every pkgar+target
when relibc rebuilds or its pkgar is missing, to prevent stale-ABI skew. But it
swept up heavy, ABI-inert toolchain packages (llvm21, clang21, lld21, rust)
identically to a 200KB daemon — forcing a 1-2h LLVM re-cook on EVERY base/relibc
bump, which cripples Mesa/KDE iteration.
These are build-time-only STATIC archives (BUILD_SHARED_LIBS=off; no runtime .so
of their own). Their libc/relibc symbol references are UNRESOLVED in the .a and
resolve at the CONSUMER final link — mesa links libLLVM*.a and resolves against
the freshly-built relibc there. So a relibc protocol change is absorbed by
relinking mesa (NOT on the preserve-list; stays invalidated), and recompiling
all of LLVM from scratch is unnecessary.
Add TOOLCHAIN_PRESERVE={llvm21,clang21,lld21,rust} skipped in both invalidation
branches, with escape hatch REDBEAR_FORCE_TOOLCHAIN_RECOOK=1 for a genuine
libc-ABI change. Trades a rare theoretical risk for a large repeated speedup;
the churn during driver/desktop work is Redox scheme/syscall shims the compilers
never call, so the default is safe.
The stash loop ended with '[ any_dirty = 0 ] && echo ...' as the
function's last command — when a fork IS dirty (any_dirty=1), the
compound returns 1 and set -e kills the build silently right after the
stash phase. Only visible with REDBEAR_ALLOW_DIRTY=1 (the dirty gate
refuses earlier otherwise). Now an explicit if + return 0.
Seventh-round integrations of the driver-manager migration's D-phase.
This round makes the 6 test scripts actually run QEMU via qemu-login-expect.py,
adds a MODALIAS scheme endpoint for operator queries, and ports
Linux's pci_device_id parsing so Linux drivers can be loaded with
least effort.
Test scripts (6, all functional now):
- test-driver-manager-parity.sh (C1 dual-mode observation): runs QEMU with
redbear-mini live.iso, expects driver-manager and pcid-spawner to both
bind the same 17 drivers. Exits 0 on PASS, 1 on FAIL, 0 on SKIP
(QEMU not available).
- test-driver-manager-active.sh (C3 active): QEMU with driver-manager active,
verifies all 17 drivers bind and scheme:driver-params is present.
- test-driver-manager-initfs.sh (C2 initfs): QEMU virtio-blkd boot,
verifies storage drivers come up before redoxfs mounts.
- test-driver-manager-hotplug.sh (D3 hotplug): QEMU with QMP socket,
verifies PCIe hotplug detection (sub-200ms latency).
- test-driver-manager-pm.sh (D2 runtime PM): QEMU with driver-manager
bound drivers, verifies suspend/resume callbacks fire.
- test-driver-manager-cutover.sh (C4 production): QEMU 3-reboot bound-set
identity check.
modalias.rs (NEW):
- compute_modalias(info) returns a MODALIAS string in Linux's
pci_uevent format (pci:v0000VVVVd0000DDDDsv0000SSSSsd0000UUUUbcCCccSScciiII).
- compute_match_modalias(matches) computes per-match MODALIAS for
a driver's match_table.
linux_loader.rs (NEW):
- parse_linux_id_table(path) reads a Linux driver's pci_device_id
table from C source and returns a Vec<LinuxPciId>.
- parse_linux_id_table_from_source(source) parses from a string.
- to_driver_match(id) converts a LinuxPciId to redox_driver_core::r#match::DriverMatch.
- Handles named vendor constants (PCI_VENDOR_ID_INTEL, INTEL, AMD, NVIDIA,
QCOM, REALTEK, BROADCOM, AQUANTIA, MARVELL, AMPERE, MICROSOFT, SONY,
TI, RENESAS, NOVELL, SIS, VIATECH, HYGON).
- Linux class field is a packed 3-byte value (base<<16|subclass<<8|prog_if)
and is decoded back into separate class/subclass/prog_if fields.
scheme.rs:
- Added /modalias endpoint. Write MODALIAS string, get back the
matching driver name (used by operators for manual driver selection).
main.rs:
- Declared modalias.rs and linux_loader.rs.
Docs:
- DRIVER-MANAGER-MIGRATION-PLAN.md v1.9 status table
- D5-AUDIT.md v1.9 update
- AGENTS.md + docs/README.md pointers to v1.9
Test totals: 39 tests across 4 crates, all passing.
§ 0.5 audit gate: 0 violations across 38 files.
Third-round integrations of the driver-manager migration's D-phase.
The pcid_interface crate (in local/sources/base submodule, see
upstream commit ddcd0870) now reads REDBEAR_DRIVER_PCI_IRQ_MODE
and REDBEAR_DRIVER_DISABLE_ACCEL at connect_default time, exposing
them as PciFunctionHandle accessors. The quirk integration is
end-to-end: driver-manager emits the env vars on spawn, pcid_interface
parses them, and the child driver reads the hints from its
PciFunctionHandle.
driver-manager (16 tests, unchanged count + 3 new for observability):
- main.rs: --list-drivers prints the config table, --dry-run
prints how many drivers would-bind/defer/blacklisted without
spawning, --export-blacklist prints the loaded blacklist.
- policy.rs: adds blacklist_module_names() iterator for export.
driver-manager v1.5 quirks.rs (created earlier at v1.4 PciQuirkFlags
work) is in the staging area and is unchanged this round.
local/scripts/driver-manager-audit-no-stubs.py:
- Drops R4 (was: 'let _ = ...' no-op detection) because Rust's
'let _ = expression' is idiomatic and not actually a stub.
- Adds R5 (stub-macro callbacks: unimplemented!/todo!/unreachable!
in callback / fn bodies) to detect dead-end fallbacks.
- Audit gate now reports 0 violations across 35 files (was 34,
pcid_interface is now in scope).
local/sources/base submodule pointer: updated to upstream commit
ddcd0870 (the pcid_interface env-var-reading commit).
Test totals: 58 tests across 4 crates, all passing.
§ 0.5 audit-no-stubs.py: 0 violations across 35 files.
Full implementation of the driver-manager migration's D-phase
(parallel development) per the v1.3 plan. The § 0.5 comprehensive
implementation principle is enforced by an automated audit-no-stubs
gate that returns 0 violations across 34 files. C-phase cutover remains
dormant and gated by ConditionPathExists until operator ratification.
redox-driver-core (28 unit + 5 integration tests):
- concurrent.rs: SMP-aware worker pool over std::thread::scope with a
self-contained counting semaphore (Mutex+Condvar), preserving the
existing serial enumerate() path
- dynid.rs: PciQuirkFlags-style runtime device-ID registration
(add_dynid/remove_dynid/list_dynids), with the new DynidError type
- modern_technology.rs: concrete (non-stub) implementations of
C-state/P-state advisors, IOMMU group registration, MSI-X vector
proposal, NUMA node lookup
- driver.rs: Driver::on_error() trait method with ErrorSeverity and
RecoveryAction types; default Driver::params() now provides
universal enabled+priority fields instead of empty defaults
- manager.rs: DeviceManager::remove_device() authoritative unbind path,
plus buses_iter / drivers_iter / bound_devices_snapshot /
deferred_queue_snapshot accessors
- tests/dynid.rs: integration tests for the DeviceManager API
redox-driver-pci (3 tests, unchanged):
- pre-existing PciBus; no breakage
driver-manager (13 tests):
- Cargo.toml: adds redox-driver-sys path dep
- quirks.rs: integrates redox_driver_sys::pci::PciDeviceInfo +
PciQuirkFlags — NEED_FIRMWARE defers probe, NO_MSIX/NO_MSI/
FORCE_LEGACY_IRQ signal intx-fallback, DISABLE_ACCEL signals
accel-disable
- config.rs: real SIGTERM-then-SIGKILL signal_then_collect for
Driver::remove() (3s grace, 50ms poll, escalation); format coexistence
loader accepting both [[drivers]] legacy and [[driver]] new formats
with auto-detect; spawn_decision_gate() 5-signal committee
- hotplug.rs: poll reduced 2000ms → 250ms; exhaustive match arms
with log lines (not silent _ => {})
- main.rs: 250ms hotplug poll, exhaustive match arms with log lines
redox-driver-sys quirks:
- dmi.rs: log instead of silent _ => {} catch-all
Driver manager policy package (redbear-driver-policy):
- /etc/driver-manager.d/00-blacklist.conf (4 driver blacklist entries)
- /etc/driver-manager.d/50-amdgpu.toml (AMD GPU driver policy)
- /etc/driver-manager.d/initfs.manifest (ordered initfs driver list)
- /etc/driver-manager.d/autoload.d/ntsync.conf (autoload ntsync module)
- /etc/driver-manager.d/README.md (explanation)
- recipe.toml: custom install script that stages into /etc/driver-manager.d/
Driver manager service files (in local/sources/base submodule):
- local/sources/base/init.d/00_driver-manager.service — dormant
(oneshot_async, ConditionPathExists=!/etc/driver-manager.d/disabled)
- local/sources/base/init.initfs.d/40_driver-manager-initfs.service —
dormant (oneshot, ConditionPathExists=!/etc/driver-manager.d/initfs-active)
Audit gate:
- local/scripts/driver-manager-audit-no-stubs.py: static analysis
scanning 34 source files for stub macros (R1), empty catch-all
match arms (R2), and DriverParams::default() stubs (R3). Returns
0 violations at v1.3.
- local/scripts/driver-manager-audit-no-stubs.sh: thin wrapper
- local/scripts/test-driver-manager-no-stubs-qemu.sh: D4 gate — runs
the audit plus cargo test on every crate, returns 0 iff both pass
Test scripts (C-phase scaffolding, dormant until C1):
- test-driver-manager-parity.sh (C1)
- test-driver-manager-active.sh (C3)
- test-driver-manager-initfs.sh (C2)
- test-driver-manager-hotplug.sh (D3)
- test-driver-manager-pm.sh (D2)
- test-driver-manager-cutover.sh (C4)
Docs:
- local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md: v1.3 status table
listing every D-phase item as Done
- local/docs/evidence/driver-manager/D5-AUDIT.md: capability-by-
capability matrix + verbatim audit output
- local/docs/HARDWARE-VALIDATION-MATRIX.md: driver-manager rows
added with v1.3 status
- local/AGENTS.md: PLANNING NOTES pointer updated to v1.3
- docs/README.md: Related Red Bear-local plans row updated to v1.3
Test totals: 49 tests across the three crates, all passing.
Audit totals: 0 violations across 34 files, all clean.
Note: local/sources/base service files (00_driver-manager.service and
40_driver-manager-initfs.service) live in a submodule and need a
separate commit there. They are NOT included in this commit.
The UHCI runtime proof grepped for the literal
'uhcid: controller initialized, polling ports'
but uhcid main.rs:535 emits it with ctrl.name interpolated mid-string:
info!("uhcid: {} controller initialized, polling ports", ctrl.name);
producing e.g. 'uhcid: 0000:00:01.2_uhci controller initialized, polling
ports'. The literal grep never matched and the proof would fail 100% of the
time at runtime.
Fix: grep with a regex anchored on the stable suffix:
grep -Eq 'uhcid: .* controller initialized, polling ports'
The ohcid, ehcid, usbhidd, and usbscsid markers were re-audited against
driver source and are all correct (ohcid main.rs:341 has no interpolation;
ehcid main.rs:294 interpolates after the matched comma prefix; all others
interpolate at line ends matched by prefix). Only the UHCI init-done marker
was broken.
Comment header and error echo updated to document the interpolated form and
point at main.rs:535 so the regex is not 'simplified' back to a literal.
No QEMU runs. bash -n passes. Verified the regex matches the real emitted
format and does not cross-match ohcid's identical suffix (the 'uhcid:' prefix
anchor disambiguates).
Create the four USB validation scripts that local/docs/USB-VALIDATION-RUNBOOK.md
references but which did not exist on disk, closing the P8-B runtime-proof gap
for the legacy host controllers and the P8-C error-injection gap for xHCI:
- test-uhci-runtime-qemu.sh (P1-B): -machine pc + piix3-usb-uhci, serial-log
proof that uhcid binds the controller and detects the attached usb-kbd.
- test-ohci-runtime-qemu.sh (P1-B): -machine pc + pci-ohci, serial-log proof
that ohcid binds the controller and detects the attached usb-kbd.
- test-ehci-class-autospawn-qemu.sh (P1-A): -machine q35 + usb-ehci + usb-kbd,
serial-log proof that ehcid enumerates the keyboard and usbhidd auto-spawns
via the unified UsbHostController trait. The existing test-ehci-qemu.sh is a
coarse usb-tablet smoke test and does NOT cover this path, so this is a full
script rather than an alias.
- test-usb-error-recovery-qemu.sh (P8-C): hot-unplug usb-storage mid-transfer
via the QEMU monitor device_del (chardev stdio mux, Ctrl-A c toggle — the
same pattern as test-xhci-device-lifecycle-qemu.sh, since qemu-login-expect.py
drives only serial and cannot reach the monitor). Proves graceful detach +
usbscsid IO-error handling with no panic.
test-xhci-device-lifecycle-qemu.sh already existed and is unchanged.
test-usb-uas-qemu.sh is intentionally NOT created: UAS is in flight in a
separate workstream and its test belongs to that change.
Proof style and harness fidelity:
- UHCI/OHCI/EHCI proofs follow the test-xhci-irq-qemu.sh serial-log grep
pattern (dual --check + interactive mode, ISO-preferred boot_args, 180s
timeout, no panic fail-marker). No guest-side checker exists that validates
legacy-controller enumeration specifically, so per the runbook's
serial-log-evidence rule they grep driver log lines instead of inventing a
guest binary.
- The error-recovery proof follows the test-xhci-device-lifecycle-qemu.sh
expect/Tcl monitor-mux pattern and reuses the existing redbear-usb-storage-check
guest binary (redbear-hwutils) to drive an active transfer — no new guest
binary is invented.
All proof markers are sourced directly from the real driver trees:
uhcid main.rs:487/535/545 (UHCI USB 1.1 at / controller initialized / connect)
ohcid main.rs:305/341/348 (OHCI USB 1.1 at / controller initialized / connect)
ehcid main.rs:154/294/560 (EHCI USB 2.0 at / controller initialized / port device)
usbhidd main.rs:221 (USB HID driver spawned with scheme)
usbscsid main.rs:190/200/163/156 (READ/WRITE IO ERROR / scheme tick / event error)
No existing scripts, qemu-login-expect.py, config/*.toml, recipes, or the
runbook were modified. The runbook's script names and --check invocations
already matched exactly, so no runbook edits were required.
Validation: bash -n passes on all four scripts. shellcheck is not installed on
this host. NO QEMU runs were performed — the host is contended by another
workload that kills QEMU processes, so validation is syntax check + pattern
fidelity review only. Runtime pass/fail is unverified.
Convert the remaining expect-based test scripts (phase1-6 runtime, usb,
wifi, bluetooth, dbus, greeter, live-iso, posix) to the stdlib python
harness, completing the migration started in 9ec00d4c81. Each script now
prefers booting the live ISO when present (falling back to harddrive.img
with snapshot=on), and retries up to 5 times when QEMU exits early or is
killed (rc 3 / 137) — the host-contention failure mode recorded in the
2026-07-20 runtime-proof status.
qemu-login-expect.py: treat an incomplete step sequence as a failure even
when a pass marker was seen partway through — partial sequences must not
count as a pass.
Post-review fixes:
- Phase 2 no longer breaks early when only --fail_marker is set: the
'if not args.pass_marker: break' guard skipped all output reads, so a
fail marker was never detected (exit 0 instead of 1). Now breaks only
when neither pass nor fail markers are configured.
- docstring referenced --pass/--fail; argparse registers
--pass_marker/--fail_marker. Align the docstring.
- retry echo said 'attempt N/3' but the loop limit is 5 attempts; say /5.
- warn and skip malformed steps (missing expect:/send: prefix) instead of
spinning in select until timeout.
Drop the host expect dependency from the PS/2, timer, IOMMU, and USB
storage (BOT) runtime proofs. local/scripts/qemu-login-expect.py drives
the guest over serial-on-stdio with ordered expect/send steps, per-step
timeouts (matching expect's per-pattern semantics), and pass/fail markers.
It distinguishes premature QEMU death (exit 3) from genuine check failure
(exit 1) so the scripts retry external interruptions without retrying real
failures. Scripts use headless -display none -vga none (fbcond serial
mirror), a 3600s per-step timeout, and a retry loop (max 5 attempts).
All six validation scripts (xhci-irq, msix, ps2, timer, iommu,
usb-storage) booted build/<arch>/<config>/harddrive.img, which is only
produced by older make-all flows and goes stale (the Jul-17 image).
Running them against it measured the wrong tree — the same trap that
produced the false '+rb0.3.0' bootloader reading and the first hub-test
failure. Each now prefers build/<arch>/<config>.iso via -cdrom and only
falls back to harddrive.img when no ISO exists. extra.img and
usb-storage.img remain as data drives in both modes.
The usb-kbd behind the QEMU usb-hub now enumerates fully: debounce ->
port reset -> enable -> second debounce -> pre-attach -> attach ->
ATTACH 5.2 -> slot 3 -> addressed -> descriptors read -> HID class match
-> 'Loading subdriver "USB HID" for port 5.2' (class 3.1 proto 1,
keyboard boot protocol).
Root cause of the final stall: an unconditional SetPortFeature
(PORT_INDICATOR) for every connected+enabled port NAK-hung on QEMU's
indicator-less hub (no control-transfer timeout), blocking the flow
before the post-enable debounce. Now gated on
wHubCharacteristics.HUB_CHAR_PORTIND like Linux has_indicators.
test-usb-hub-qemu.sh: check #5 now requires the hub-child subdriver
line ('Loading subdriver "USB HID" for port <root>.<child>') so a
root-port HID (tablet) can no longer satisfy it — closes a false-
positive hole. Timeout raised to 360s for slow TT-path driver bring-up.
Docs (plan P3-A runtime validation + matrix): full hub + hub-child
chain recorded as QEMU-proven; remaining items (intermittent reactor
startup race, slow TT-path Evaluate Context) noted.
Hub enumeration is quick, but a hub-child's class driver then performs
its own descriptor/control transfers on the slow emulated TT path, and
the guest clock runs several times slower than wall time under load.
180s cut the boot before a hub-child HID driver could finish
registering after being spawned.
Serial output from dozens of concurrent daemons interleaves mid-line,
so full-sentence matches like 'usbhubd: 8 port(s) detected' fail even
when the content is present (observed mangled as 'usbhubd: 548: port(s)
detected'). Match short fragments ('port(s) detected', 'change
detection', 'registered producer') that survive interleaving.
The 'USB HUB driver spawned' log line is emitted before setup_logging
and never reaches the serial console, so check #2 could never pass.
Use the hub-descriptor read line (emitted only after XhciClientHandle
open + 8-port descriptor fetch succeed) as the spawn proof, and fold
the old duplicate descriptor check into it.
Cat 1 discovery treated every local/recipes/*\/source/Cargo.toml as an
in-house crate, including git-fetched upstream sources like brush
(git = github.com/reubeno/brush). Rewriting upstream crate versions to
the branch version broke upstream-internal version requirements
(brush-shell was forced to 0.3.1 while brush required ^0.4.0 —
'failed to select a version for the requirement brush-shell = ^0.4.0').
Guard: skip any crate whose Cargo.toml is not tracked by the parent
repo. In-house crates are tracked trees (no independent .git); fetched
sources are gitignored and untracked. Restores correct classification:
75 crates checked (12 fetched-source crates now excluded), drift 0,
brush cooks successfully again.
- sync-versions.sh: 11 brush workspace crates 0.x -> 0.3.1 (Cat 1
in-house version policy).
- test-usb-hub-qemu.sh: boot the live ISO (canonical build-redbear.sh
artifact) instead of harddrive.img, which is only produced by older
make-all flows and goes stale — a stale Jul-17 image with a
pre-version-sync bootloader (+rb0.3.0) masked the current build and
crashed the first proof attempt. Falls back to harddrive.img only
when no ISO exists.
The script cd's into the fork dir for the clean-tree check (line ~202)
and never returns to PROJECT_ROOT. Every subsequent relative
'cd "$fork_dir"' subshell then fails with 'No such file or directory',
making single-fork and multi-fork runs always FAIL at the upstream-ref
resolution step. Make fork_dir absolute at assignment so all subshell
cd/git calls work regardless of current directory.
Found while attempting the base fork sync (verify-fork-functions gate).
Tier 1 message fixes (Part 5.3):
- M18/M19 (build-redbear.sh:523-524): reworded patch-application messages
to reflect local fork model (forks have patches committed; recipe patches
for non-fork recipes applied atomically by repo fetch)
- M46 (build-redbear.sh:923): 'immutable archives' → 'local forks'
Tier 2 doc consolidation (Part 7):
- GRUB-INTEGRATION-PLAN.md: updated all 'make all CONFIG_NAME=' commands
to canonical './local/scripts/build-redbear.sh' equivalents
- SLEEP-IMPLEMENTATION-PLAN.md: archived (referenced 0.2.4 branch, pre-0.3.1)
Assessment doc Part 7 updated: all Tier 1 (items 1-6) and Tier 2 (items 7-13)
marked as verified complete with per-item status.
All Q1-Q10 quality improvement opportunities from Part 6.2 and all Tier 1-3
items from Part 7 are now resolved.
Tier 3 code improvements (from BUILD-SYSTEM-ASSESSMENT-2026-07-18 Part 6.2):
- Q2: Add run_command_with_retry() helper with exponential backoff (1s, 2s, 4s).
Wrap download_wget and git clone with 3 attempts. Git clone closure cleans
partial tmp dir between retries (git refuses non-empty clone targets).
- Q3: Preserve auto_deps.toml alongside dep_hashes.toml in binary store publish
(repo_builder.rs). Restore path prefers the preserved copy, falling back to
declared-depends-only reconstruction only when the preserved copy is absent
(e.g. published by an older cookbook). Preserves full ELF dynamic dep graph.
- Q4: DepHashes::read now returns Result<Option<Self>, String> discriminating
'missing' (legitimate first build, fall back to mtime) from 'corrupt' (loud
WARN + force rebuild). Closes a silent-swallow gap where a corrupt
dep_hashes.toml produced an incorrect mtime-fallback rebuild.
- Q6: Standardize error reporting in repo.rs nonstop path to {:#} format,
matching the pattern established in the earlier Tier 1 message commit.
Tier 1 message fixes (remaining items from assessment Part 5.3/5.4):
- M26: build-redbear.sh:569 '30-60 minutes' -> config-dependent range
- A6/A8: Makefile container messages add remediation hint
- B3: mk/config.mk sccache hint adds install guidance
- H2: mk/qemu.mk Unsupported ARCH lists supported values
- mk/redbear.mk comment 'fully-patched' -> 'versioned'
Verification: cargo check 0 errors, cargo test --lib 35/35 passed,
cargo clippy 0 new warnings vs baseline, make -n live + validate clean.
- build-redbear.sh: detect changes to the 4 forks the staleness loop missed
(userutils pkgar; syscall/libredox/redox-scheme crate path-deps force a full
userspace relink) — prevents stale-binary skew (bash -n validated).
- glib: drop the stale '#undef AT_FDCWD' Redox workaround — relibc now provides
faccessat()/AT_FDCWD, and glib's HAVE_FACCESSAT path needs AT_FDCWD.
- mesa: remove the dropped '-Dosmesa=true' meson option (unknown option) and
guard the osmesa.pc pkg-config edit.
- libinput: unblocked by syncing the fresh relibc libc.a (with timerfd_*) into
the stale prefix sysroot (prefix-sysroot staleness — see notes).
The kernel event scheme now implements kdup, so dup() of an epoll fd works
and tokio's registry.try_clone() succeeds — fixing the tokio runtime EINVAL
that killed every zbus daemon and the brush login shell.
build-redbear.sh: gate the userspace build/sysroot clean on relibc/base
(the forks userspace links) instead of any low-level fork, so a kernel-only
change rebuilds the kernel + initfs + image without a full userspace re-cook.
relibc is statically linked into every userspace binary, so a relibc change
invalidates every consumer, not just the 4 initfs-critical packages the old
ABI_CRITICAL_PKGS list covered. A stale consumer silently bakes in old relibc
behaviour; diagnosing against such stale binaries wastes enormous time. Now:
if relibc rebuilds, ALL package pkgars + recipe build trees are invalidated
for a clean relink; otherwise any consumer pkgar older than relibc.pkgar (the
interrupted-build skew that shipped a broken login image) is invalidated.
Also add a temporary SESSIOND_DIAG probe that tries each tokio runtime config
and logs which one EINVALs, to pinpoint the tokio-runtime failure.
Mini now boots (q35/KVM) all the way to the getty "Red Bear login:" prompt
on VT2 with zero kernel panics. Root-cause fixes across submodules + config:
- config: 00_base.service zsh->mkdir (a full shell startup hangs an init
oneshot; the earlier 'echo/mkdir also hang' result was a silent config
override running zsh). 00_ptyd.service notify->{scheme=pty} (ptyd signals
readiness via its scheme fd; notify made init block on a byte forever).
- kernel: wrmsr_safe/rdmsr_safe #GP recovery so /scheme/sys/msr can't panic
the kernel (cpufreqd's P-state MSR write #GP'd on KVM, halting the boot
before login). base: ptyd scheme type + hwd ACPI enum -> debug (noise).
installer: warn on config [[files]] override. relibc/bootloader: prior
getrlimit + warning-demotion pointers.
- build-redbear.sh: fix host-fstools staleness (installer/redoxfs never
rebuilt on source change), prefix rebuild-every-build (touch libc.a), add
concurrent-build flock.
Submodule pointers: base 8aa8616d, installer 460d9530, kernel 155d01b1,
relibc a7663b3a, bootloader 6e119641.
The redbear-bare target (added in 48a6f4c20b) was not registered in
the build dispatchers. Running build-redbear.sh redbear-bare
silently exited with 'ERROR: Unknown config redbear-bare'.
Fix:
- build-redbear.sh: extend the case statement + usage block + error
message to include redbear-bare
- integrate-redbear.sh: add config/redbear-bare.toml to the configs
array so source-tree integration picks up the bare target too
- build-all-isos.sh: include redbear-bare in the targets list
This closes the gap where the bare target existed as a config file
and as a recipe branch (REDBEAR_BARE_INITFS) but was invisible to
the build dispatch layer.
(NO AI attribution)
Round-25 fix landed the bare initfs conditional in
recipes/core/base-initfs/recipe.toml but the cookbook does NOT parse
[build.env] sections in TOML configs. The REDBEAR_BARE_INITFS=1
env var I put in redbear-bare.toml was silently ignored.
Fix: propagate REDBEAR_BARE_INITFS through build-redbear.sh's make live
invocation. When CONFIG=redbear-bare and the operator has not already
exported REDBEAR_BARE_INITFS, auto-set it to 1 so the bare initfs
branch is triggered. Also propagates any pre-existing REDBEAR_BARE_INITFS
through the make call (override-only).
Also rewrote the [build.env] section in redbear-bare.toml to a
comment-only section explaining the dispatch mechanism, since the
cookbook parser ignores it.
(NO AI attribution)
Per local/AGENTS.md § "BRANCH AND SUBMODULE POLICY (ABSOLUTE)":\neach Red Bear fork worktree must be on the canonical\n"submodule/<name>" branch. Until now, the build system had NO\ncode enforcing this — drift was caught only by operator discipline\n(Round-21 hand-normalized 6 of 9 forks).\n\nAdd a new redbear_check_fork_branches() function called as a peer of\nthe existing dirty-source gate. It iterates REDBEAR_FORK_SOURCES,\nreads each fork worktree's current branch via 'git branch\n--show-current', and compares to 'submodule/<label>'. On mismatch\nthe build aborts with a clear error message and a documented fix\nrecipe. Escape hatch: REDBEAR_ALLOW_WRONG_BRANCH=1.
The script uses '${BRANCH_VERSION:-0.0.0}' as the +rb suffix when
bumping a fork to a new upstream version. BRANCH_VERSION was never
set, so any fork bump would have produced 'X.Y.Z+rb0.0.0' instead
of the correct 'X.Y.Z+rb0.3.2' (or whichever branch is current).
Derive BRANCH_VERSION from 'git branch --show-current' using the same
pattern as local/scripts/build-redbear.sh:158-165. Falls back to
'0.0.0' if the branch name doesn't match semver (e.g., on 'master').
(NO AI attribution)
The verify-overlay-integrity.sh script has two blind spots for stale
symlink detection:
1. find recipes -maxdepth 3 misses paths at depth 4+
2. only checks targets under /local/recipes/, misses /local/patches/
This adds a parallel scan that finds all dangling symlinks under recipes/
without maxdepth, classifies them by target path, and reports each with a
suggested action. Pure diagnostic — does not modify any files.
Enables preventive detection of the recipes/wip/x11/mesa-x11/source
orphan and recipes/core/base/redox.patch pointer-rot that triggered the
build integrity warnings on this session's rebuilds.
(NO AI attribution in commit message.)
Archived mega-patches (kernel/redox.patch, base/redox.patch, relibc/redox.patch,
installer/redox.patch, bootloader/redox.patch, P2-boot-runtime-fixes) were
consolidated into modular P0-...P9- patches during Phase 2/3 cleanup but the
integrity checker still expected them. Removed from EXPECTED_PATCH_SYMLINKS
and CRITICAL_PATCHES arrays. Fixed qt6-wayland-smoke symlink.
Overlay integrity check now PASSES (0 errors).
When recipes/<cat>/<name> is a directory symlink into local/recipes/,
creating a file-level symlink at recipes/<cat>/<name>/recipe.toml
resolves through the dir symlink and CORRUPTS the real file at
local/recipes/<cat>/<name>/recipe.toml (replaces it with a broken
self-referencing symlink).
This was the root cause of 186 'broken recipe.toml' auto-repairs
on every build. Called via apply-patches.sh line 369.
Broken recipe.toml corruption also affects tracked symlinks in
recipes/ tree (e.g. recipes/libs/libxau/recipe.toml). Extended
the auto-repair find to cover both local/recipes/ and recipes/.
Detects broken recipe.toml symlinks in local/recipes/ (self-referencing
corruption from unknown source) and auto-restores from git before build.
Prevents 'Package not found' errors when recipe.toml files are unreadable.
apply-patches.sh: 005-qtbase signature now checks correct path
(recipes/wip/qt/qtbase, not recipes/libs/qtbase) and respects
local recipe override. Qt is desktop-only (redbear-full target).
check-fork-drift.sh: skip diverged forks (kernel, bootloader, installer)
to suppress spurious DRIFT warnings. These forks intentionally diverge
from upstream per fork-upstream-map.toml.
integrate-redbear.sh: add safety guard — refuse to symlink any path
ending in 'recipe.toml'. 185 local recipe.toml files were corrupted
into broken self-referencing symlinks by an earlier build session.
All restored from git. Guard prevents reoccurrence.
check-fork-drift.sh: diverged forks (kernel, bootloader, installer)
are intentionally ahead of upstream — skip them to suppress spurious
DRIFT warnings during build preflight.
apply-patches.sh: 005-qtbase patch signature now checks correct path
(recipes/wip/qt/qtbase/recipe.toml) and respects local recipe override.
Patch creates recipes/wip/qt/qtbase/recipe.toml but the signature
check looked for REDBEAR marker in recipes/libs/qtbase/recipe.toml
(wrong path). Also added check for local recipe existence (takes
precedence per local-over-WIP policy).
This was causing overlay integrity check failures during redbear-mini
builds even though Qt is irrelevant for the console target.
Common function names (new, read, write, parse, get, set, remove, etc.)
appear in many unrelated files — cross-file search produces false MOVED
classifications (e.g., fn new() in ipcd matches fn new() in xhcid).
The case-based guard skips cross-file search for 40+ common function names.
These must be handled via the .verify-fork-functions.exclude mechanism
instead — operator decides if removal was intentional or accidental.
Results: kernel 19→17 (kcall×2 correctly MOVED to user.rs, eq/hash
correctly blocked from false MOVED to fdstat.rs)
upgrade-forks.sh:
- --no-fetch: use cached upstream refs (no network required)
- --force-reapply: force rebase even when 0 commits behind upstream
Automatically detects missing functions via verify-fork-functions.sh
and triggers reapply when RB cherry-picks dropped upstream code.
verify-fork-functions.sh:
- Cross-file search: when a function is missing from its upstream file,
search ALL fork .rs files for renamed/moved equivalents (→ MOVED)
- Per-fork exclusion list: .verify-fork-functions.exclude for
intentionally removed/replaced functions (→ EXCLUDED)
- Only truly missing (not found anywhere, not excluded) = violations
build-preflight.sh:
- Updated fix suggestion to --no-fetch --force-reapply
Results: installer 2→0 (exclusion+move), kernel 19→15 (4 moved),
base 56→44 (12 moved). Remaining missing functions are known RB
replacements pending exclusion entries.
- PATCH-PRESERVATION-AUDIT: add Phase 16.1 to cumulative reduction table
(122→0 orphans, Round 17); update operator test section with all 6 modes;
replace stale 'Round 3 final' re-run with current Round 17 verification
- TOOLS.md: add --regen and --dry-run flags; clarify default is opt-in
- HOOKS.md: add --regen and --dry-run to sync-versions.sh option list
- REGEN_LOCKFILES defaults to 0 (opt-in, not opt-out)
- New --regen flag explicitly enables lockfile regeneration
- New --dry-run flag: snapshots each Cargo.lock, regens, diffs, reverts
Reports per-lockfile changes that WOULD occur without modifying files
- Fixed --regen-only deadlock: CHECK_ONLY=1 no longer blocks regen
(mode_regen_only gate added to CHECK_ONLY skip check)
- Fixed ROOT_DRIFT unbound variable in --regen-only mode
(: ${ROOT_DRIFT:=0} before summary section)
- Moved regen_lockfile_for() definition before dry-run block
(was defined after call site — caused 'command not found')
Replaces the 6 UNKNOWN entries in the post-loop summary with
specific status derived from fork-upstream-map.toml when the
main loop doesn't set a per-fork status.
Fallback logic for forks without explicit FORK_STATUS:
- diverged mode → DIVERGED-BYPASS
- tracked mode → TRACKED-PASS
- snapshot mode → SNAPSHOT-PASS (with actual tag from map)
- not in map → NOT-MAPPED
This makes every fork's status visible at a glance:
=== Post-verification fork status ===
bootloader DIVERGED mode=diverged; content check skipped
installer DIVERGED mode=diverged; content check skipped
kernel DIVERGED mode=diverged; content check skipped
libredox PASS content matches upstream 0.1.18
base TRACKED-PASS tracked-fork, version label passed
redoxfs SNAPSHOT-PASS snapshot fork, version label 0.9.1
relibc SNAPSHOT-PASS snapshot fork, version label 0.2.5
...
Bug fix: upstream_tag variable was stale from the last loop
iteration. Now reads the correct tag from fork-upstream-map.toml.
Per assessment G2 from Round 11: verify-fork-versions.sh silently
skipped content checks for forks whose upstream tags don't exist,
making failures invisible. This adds a post-loop summary table
that enumerates each fork's verification status.
Added per-fork status tracking:
- DIVERGED: fork in diverged mode (content check skipped)
- NO_UPSTREAM_TAG: upstream tag doesn't exist (content check skipped)
- PASS: content matches upstream tag
- SKIP: no Cargo.toml (not a tracked fork)
- UNKNOWN: not yet classified (future refinement)
The summary table prints after the per-fork warn/error output,
giving operators a single-view snapshot of all 10 forks:
=== Post-verification fork status ===
fork status detail
---------- ---------------- ------
base UNKNOWN not checked
bootloader DIVERGED mode=diverged; content check skipped
installer DIVERGED mode=diverged; content check skipped
kernel DIVERGED mode=diverged; content check skipped
libredox PASS content matches upstream 0.1.18
...
Bug fix: added cd "$ROOT" before post-loop summary because the
per-fork content-check loop cd's into each fork directory.