Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-881GitHub issuePublicDecided· Out of scope

Suspend/resume support for vintage MacBook Pro 13" 2017 (MacBookPro14,1): default `deep` sleep breaks Thunderbolt on resume — working s2idle enablement, patches forthcoming

Reported by orospakr · filed Sep 7, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Suspend/resume support for vintage MacBook Pro 13" 2017 (MacBookPro14,1): default `deep` sleep breaks Thunderbolt on resume — working s2idle enablement, patches forthcomingrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

Apple MacBookPro14,1 (13″ 2017, 2× TBT3), Intel Core i7-7660U, Iris Plus 640, Apple EFI 429.100.7.0.0, kernel 7.1.9-arch1-2, Omarchy 4.0.1-1

What's wrong?

Omarchy on a 2017 13″ MacBook Pro (MacBookPro14,1 — a great vintage-Mac target for the distro) has broken lid-close suspend out of the box. This is a hardware-enablement report: we've spent a couple of weeks root-causing it on real hardware, have a validated fix, and intend to follow up with patches. Filing the findings first so the work happens in the open.

Symptoms with the default config (mem_sleep = deep, i.e. ACPI S3)

  1. Resume takes 75–107 seconds (vs ~1.3 s once fixed), and the machine comes back with the Thunderbolt controller dead and its USB-C/xHCI ports hot-removed. Every S3 cycle, 100% reproducible.
  2. Worse: if anything is plugged into a Thunderbolt port when the lid closes, the Mac's own EFI firmware disables the Thunderbolt PCIe root port during its S3 resume script — before the kernel runs a single instruction. Nothing short of a cold boot brings the port back. Reproduced 8/8; we eliminated 11 candidate OS-level countermeasures one variable at a time (wake-source disarming, D-state pinning, driver unbinding, link-state forcing, PD-controller mailbox commands, …). macOS clearly slept in S3 with Thunderbolt devices attached, so there is a firmware handshake it performs that we haven't found yet — see "Further investigation" below.
  3. Switching to s2idle alone doesn't fix it either: the PCI core's skip_bus_pm policy (for platforms without ACPI low-power-S0 support, which includes this Mac) skips config-space restore on resume — but the Thunderbolt controller genuinely powers down and loses its config space during s2idle, so it still comes back dead (-ESHUTDOWN from the NHI until module reload).

Root causes (three distinct issues: two Linux bugs, one undocumented Apple firmware contract)

  • Linux bug 1 (deep/S3): PCI state-save ordering. Device suspend runs children-first, so the Thunderbolt NHI's suspend_noirq puts the whole Alpine Ridge controller (JHL6540/DSL6540) to sleep before the PCIe bridges above it save their config space — they snapshot all-ones and restore garbage on wake. macOS avoids this by saving PCI state early (IOPCIFamily); mainline Linux does not.
  • Apple EFI behavior (deep/S3, attached): the firmware's S3 resume boot script function-disables root port RP05 (00:1c.4) ~4–6 ms after wake whenever something is physically present on the Thunderbolt port. The trigger is physical presence, and no Linux-side mechanism we tested masks it. Since macOS handled attached-S3 fine, this is presumably not a firmware bug so much as a firmware contract — some pre-sleep handshake (leading candidate: NVRAM/EFI-variable state consumed by the S3 resume script) that macOS performs and Linux doesn't. Until that half of the dance is worked out, S3 with anything attached is a soft-brick, so s2idle is the safe default.
  • Linux bug 2 (s2idle): skip_bus_pm assumes devices keep their config space across s2idle; the Alpine Ridge doesn't (the thunderbolt driver's own tb_lc_set_sleep() powers it down), and the skipped restore kills it.

What works (validated)

s2idle + a ~390-line out-of-tree module (tb_ar_shim) that attaches a dev_pm_domain to the Alpine Ridge upstream bridge and does two things: saves the controller's subtree config space early in suspend_late (while it's still readable), and restores it parents-first in resume_noirq (since the PCI core won't). Because s2idle never executes the EFI S3 boot script, the firmware bug can't fire at all.

Validation: 22 s2idle cycles with zero Thunderbolt failures, resume in 1.32–1.40 s, including lid-close with Wi-Fi loaded (reconnects in ~1 s). Known trade-offs: s2idle drains more battery than S3 (this platform has no firmware S0ix assist), and the keyboard backlight stays lit during sleep when the lid is open (separate one-line applespi fix: the LED lacks LED_CORE_SUSPENDRESUME) — the hardware appears to cut the backlights itself when the lid is closed.

Forthcoming

We'll follow up with a first pass of patches for s2idle enablement on this device:

  1. The Alpine Ridge dev_pm_domain fix, delivered as a DKMS package (build-time-applied patch/module), so it survives kernel updates without shipping a custom kernel.
  2. A rule that selects s2idle by default on this DMI model (MacBookPro14,1 / Mac-B4831CEBD52A0C4C), so lid-close is safe out of the box — critically, so a Thunderbolt device left plugged in during deep sleep can never soft-brick the port until the next cold boot.

Longer-term we intend to upstream the two Linux-side fixes to mainline (DECLARE_PCI_FIXUP_SUSPEND on the Alpine Ridge IDs gated on x86_apple_machine, plus a linux-pci discussion of the skip_bus_pm restore-skip), at which point the DKMS piece can be dropped.

Further investigation: macOS' half of the S3 dance

s2idle is the correct safe default, but it costs battery relative to S3 (no firmware S0ix assist on this platform), and macOS proves attached-S3 is achievable. Working out what macOS tells the firmware before sleeping is the open research item that could restore full S3:

  • Dump and decode the EFI S3 resume boot script from ACPI NVS (read-only /dev/mem) to see what condition gates the RP05 function-disable.
  • Survey EFI variables (read-only) for sleep-related state macOS sets on the way down — the leading theory is an NVRAM/EFI-variable handshake the resume script consumes.
  • Analyze the CD3215 PD-controller firmware interface further; its mailbox accepts some macOS commands but rejected the sleep 4CC on this firmware revision, so the macOS-side sequencing may differ from what AppleHPM sources suggest.
  • Cross-reference IOPCIFamily / AppleThunderboltNHI behavior for pre-S3 steps beyond the early PCI save we already replicated.

If that handshake is found, the s2idle rule becomes a preference rather than a necessity.

Further reading

omarchy-debug-tinymac-trimmed.log

Happy to test candidate approaches on the hardware — the machine is instrumented for remote suspend/resume experiments.

View raw text
### System details

Apple MacBookPro14,1 (13″ 2017, 2× TBT3), Intel Core i7-7660U, Iris Plus 640, Apple EFI 429.100.7.0.0, kernel 7.1.9-arch1-2, Omarchy 4.0.1-1

### What's wrong?

Omarchy on a 2017 13″ MacBook Pro (MacBookPro14,1 — a great vintage-Mac target for the distro) has broken lid-close suspend out of the box. This is a hardware-enablement report: we've spent a couple of weeks root-causing it on real hardware, have a validated fix, and intend to follow up with patches. Filing the findings first so the work happens in the open.

### Symptoms with the default config (`mem_sleep = deep`, i.e. ACPI S3)

1. **Resume takes 75–107 seconds** (vs ~1.3 s once fixed), and the machine comes back with the Thunderbolt controller dead and its USB-C/xHCI ports hot-removed. Every S3 cycle, 100% reproducible.
2. **Worse: if anything is plugged into a Thunderbolt port when the lid closes**, the Mac's own EFI firmware disables the Thunderbolt PCIe root port during its S3 resume script — before the kernel runs a single instruction. Nothing short of a **cold boot** brings the port back. Reproduced 8/8; we eliminated 11 candidate OS-level countermeasures one variable at a time (wake-source disarming, D-state pinning, driver unbinding, link-state forcing, PD-controller mailbox commands, …). macOS clearly slept in S3 with Thunderbolt devices attached, so there is a firmware handshake it performs that we haven't found yet — see "Further investigation" below.
3. **Switching to s2idle alone doesn't fix it either**: the PCI core's `skip_bus_pm` policy (for platforms without ACPI low-power-S0 support, which includes this Mac) skips config-space restore on resume — but the Thunderbolt controller genuinely powers down and loses its config space during s2idle, so it still comes back dead (`-ESHUTDOWN` from the NHI until module reload).

### Root causes (three distinct issues: two Linux bugs, one undocumented Apple firmware contract)

- **Linux bug 1 (deep/S3):** PCI state-save ordering. Device suspend runs children-first, so the Thunderbolt NHI's `suspend_noirq` puts the whole Alpine Ridge controller (JHL6540/DSL6540) to sleep *before* the PCIe bridges above it save their config space — they snapshot all-ones and restore garbage on wake. macOS avoids this by saving PCI state early (IOPCIFamily); mainline Linux does not.
- **Apple EFI behavior (deep/S3, attached):** the firmware's S3 resume boot script function-disables root port RP05 (00:1c.4) ~4–6 ms after wake whenever something is physically present on the Thunderbolt port. The trigger is physical presence, and no Linux-side mechanism we tested masks it. Since macOS handled attached-S3 fine, this is presumably not a firmware *bug* so much as a firmware *contract* — some pre-sleep handshake (leading candidate: NVRAM/EFI-variable state consumed by the S3 resume script) that macOS performs and Linux doesn't. Until that half of the dance is worked out, S3 with anything attached is a soft-brick, so s2idle is the safe default.
- **Linux bug 2 (s2idle):** `skip_bus_pm` assumes devices keep their config space across s2idle; the Alpine Ridge doesn't (the thunderbolt driver's own `tb_lc_set_sleep()` powers it down), and the skipped restore kills it.

### What works (validated)

**s2idle + a ~390-line out-of-tree module** (`tb_ar_shim`) that attaches a `dev_pm_domain` to the Alpine Ridge upstream bridge and does two things: saves the controller's subtree config space early in `suspend_late` (while it's still readable), and restores it parents-first in `resume_noirq` (since the PCI core won't). Because s2idle never executes the EFI S3 boot script, the firmware bug can't fire at all.

Validation: 22 s2idle cycles with zero Thunderbolt failures, resume in 1.32–1.40 s, including lid-close with Wi-Fi loaded (reconnects in ~1 s). Known trade-offs: s2idle drains more battery than S3 (this platform has no firmware S0ix assist), and the keyboard backlight stays lit during sleep when the lid is open (separate one-line `applespi` fix: the LED lacks `LED_CORE_SUSPENDRESUME`) — the hardware appears to cut the backlights itself when the lid is closed.

### Forthcoming

We'll follow up with a first pass of patches for s2idle enablement on this device:

1. The Alpine Ridge `dev_pm_domain` fix, delivered as a **DKMS package** (build-time-applied patch/module), so it survives kernel updates without shipping a custom kernel.
2. A rule that **selects s2idle by default on this DMI model** (MacBookPro14,1 / Mac-B4831CEBD52A0C4C), so lid-close is safe out of the box — critically, so a Thunderbolt device left plugged in during `deep` sleep can never soft-brick the port until the next cold boot.

Longer-term we intend to upstream the two Linux-side fixes to mainline (`DECLARE_PCI_FIXUP_SUSPEND` on the Alpine Ridge IDs gated on `x86_apple_machine`, plus a linux-pci discussion of the `skip_bus_pm` restore-skip), at which point the DKMS piece can be dropped.

### Further investigation: macOS' half of the S3 dance

s2idle is the correct *safe* default, but it costs battery relative to S3 (no firmware S0ix assist on this platform), and macOS proves attached-S3 is achievable. Working out what macOS tells the firmware before sleeping is the open research item that could restore full S3:

- Dump and decode the **EFI S3 resume boot script** from ACPI NVS (read-only `/dev/mem`) to see what condition gates the RP05 function-disable.
- **Survey EFI variables** (read-only) for sleep-related state macOS sets on the way down — the leading theory is an NVRAM/EFI-variable handshake the resume script consumes.
- Analyze the **CD3215 PD-controller firmware** interface further; its mailbox accepts some macOS commands but rejected the sleep 4CC on this firmware revision, so the macOS-side sequencing may differ from what AppleHPM sources suggest.
- Cross-reference **IOPCIFamily / AppleThunderboltNHI** behavior for pre-S3 steps beyond the early PCI save we already replicated.

If that handshake is found, the s2idle rule becomes a preference rather than a necessity.

### Further reading

- Full investigation writeup (three bugs, elimination table, sequence diagrams, validation ledger, reading guide): https://claude.ai/code/artifact/911dba07-7053-4dcc-98dd-d0eaacac9ef1
- `omarchy debug` log: attached in a comment below (trimmed of firewall log spam) 

[omarchy-debug-tinymac-trimmed.log](https://github.com/user-attachments/files/31895722/omarchy-debug-tinymac-trimmed.log)

Happy to test candidate approaches on the hardware — the machine is instrumented for remote suspend/resume experiments.

  • omarchy-debug-tinymac-trimmed.log

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 11:01 UTC