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-962GitHub issuePublicDecided· Out of scope

Power panel invents a "Charge limit / Holding" state on hardware with no charge-control support

Reported by gabamnml · filed Sep 4, 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

Power panel invents a "Charge limit / Holding" state on hardware with no charge-control supportrevision 1 · captured 2026-09-28 21:24 UTC via poll

What happens

On a MacBookPro12,1 the power panel shows a charge-threshold UI for hardware that has no charge-control interface at all. On AC at 94.7% it renders:

Charge limit    -
Battery state   Holding

Apple's SMC deliberately does not top the battery back up until it falls to roughly 93–95%; this is the same behaviour macOS surfaces as "Battery is charged". UPower therefore reports:

state:       fully-charged
percentage:  94.7402%
energy-rate: 0 W

The panel reads that as a user-configured charge limit. The battery exposes no charge-control interface whatsoever:

$ for f in charge_control_end_threshold charge_control_start_threshold charge_behaviour; do
    printf '%-32s %s\n' "$f" "$([ -e /sys/class/power_supply/BAT0/$f ] && echo exists || echo 'does not exist')"
  done
charge_control_end_threshold      does not exist
charge_control_start_threshold    does not exist
charge_behaviour                  does not exist

Expected

The normal charged/charging presentation — which omarchy-battery-status already produces correctly.

Root cause: the CLI and the panel disagree

bin/omarchy-battery-status gates the whole charge_holding block on a real hardware threshold being present (lines 88–97):

charge_holding=false
if [[ $ac_online == "true" && -n $threshold_end ]]; then       # <-- threshold must exist
  if [[ $state == "pending-charge" ]]; then
    charge_holding=true
  elif [[ $state == "fully-charged" ]] && (( percentage < 99 )); then
    charge_holding=true
  elif [[ $state == "charging" && $charge_idle == "true" ]] && (( threshold_end < 99 && percentage >= threshold_end )); then
    charge_holding=true
  fi
fi

shell/plugins/panels/power/Model.js mirrors the same three conditions but drops the -n $threshold_end half of the guard — it only checks that we are on AC (lines 52–64):

function chargeThresholdActive(device, onBattery, states) {
  var d = device || {}
  var s = states || {}
  if (!(d && d.isPresent && !onBattery)) return false          // <-- no threshold check

  var fraction = batteryFraction(d)
  if (d.state === s.Discharging) return false
  if (d.state === s.PendingCharge) return true
  if (d.state === s.FullyCharged && fraction < 0.99) return true   // <-- fires here
  if (d.state !== s.Charging || fraction >= 0.99) return false

  return Number(d.changeRate || 0) <= 0.2 || Number(d.timeToFull || 0) >= 8 * 60 * 60
}

So the two components disagree on the same machine. The CLI is right:

$ omarchy battery status --shell
percentage      94%
state           fully-charged
rate            0W
size            71Wh
time
cycles          113

while plugins/panels/power/Panel.qml:444-449 renders "Charge limit" / "Holding".

A secondary symptom: because the script only emits the threshold field when threshold_end is non-empty (bin/omarchy-battery-status:114), batteryInfo.threshold is undefined here, so Panel.qml:445 falls back to "-". The panel ends up showing a labelled "Charge limit" row with no value.

Steps to reproduce

Any machine that has no charge_control_* sysfs attributes and whose firmware reports fully-charged below 99% while on AC. Apple laptops do this by design:

  1. Charge to ~95%, unplug briefly, plug back in.
  2. Wait for the SMC to settle into not-recharging (current_now reads 0, status reads Full).
  3. Open the power panel.

Suggested fix

Give Model.chargeThresholdActive() the same guard the shell script has — only treat the state as a held charge when a threshold is actually known. Since the script already omits the threshold field when there is none, Panel.qml could pass batteryInfo.threshold in and bail out when it is empty, keeping the two implementations in agreement.

System

  • Omarchy 4.0.2-1
  • Kernel 7.1.9-arch1-2, Hyprland 0.56.2
  • Apple MacBookPro12,1 (13" Retina Early 2015), Intel Core i5-5287U (Broadwell)
  • Battery: SMP bq20z451, 71.2/74.9 Wh (95.1% health), 113 cycles

Related

  • #10121 (T2 Macs: charge limiting unreachable) asks that any future charge-limit support "degrade cleanly rather than assume charge_control_end_threshold exists". This is the same class of problem in an existing component: the panel already assumes it. Both machines are Apple laptops with no charge_control_* at all — pre-T2 here, T2 there.
  • #9586 concerns the threshold value being wrong when one genuinely exists (UPower's fixed ThinkPad default). Distinct from this, which is a threshold being reported where none exists.
View raw text
## What happens

On a MacBookPro12,1 the power panel shows a charge-threshold UI for hardware that has no charge-control interface at all. On AC at 94.7% it renders:

```
Charge limit    -
Battery state   Holding
```

Apple's SMC deliberately does not top the battery back up until it falls to roughly 93–95%; this is the same behaviour macOS surfaces as "Battery is charged". UPower therefore reports:

```
state:       fully-charged
percentage:  94.7402%
energy-rate: 0 W
```

The panel reads that as a user-configured charge limit. The battery exposes no charge-control interface whatsoever:

```
$ for f in charge_control_end_threshold charge_control_start_threshold charge_behaviour; do
    printf '%-32s %s\n' "$f" "$([ -e /sys/class/power_supply/BAT0/$f ] && echo exists || echo 'does not exist')"
  done
charge_control_end_threshold      does not exist
charge_control_start_threshold    does not exist
charge_behaviour                  does not exist
```

## Expected

The normal charged/charging presentation — which `omarchy-battery-status` already produces correctly.

## Root cause: the CLI and the panel disagree

`bin/omarchy-battery-status` gates the whole `charge_holding` block on a real hardware threshold being present (lines 88–97):

```bash
charge_holding=false
if [[ $ac_online == "true" && -n $threshold_end ]]; then       # <-- threshold must exist
  if [[ $state == "pending-charge" ]]; then
    charge_holding=true
  elif [[ $state == "fully-charged" ]] && (( percentage < 99 )); then
    charge_holding=true
  elif [[ $state == "charging" && $charge_idle == "true" ]] && (( threshold_end < 99 && percentage >= threshold_end )); then
    charge_holding=true
  fi
fi
```

`shell/plugins/panels/power/Model.js` mirrors the same three conditions but drops the `-n $threshold_end` half of the guard — it only checks that we are on AC (lines 52–64):

```js
function chargeThresholdActive(device, onBattery, states) {
  var d = device || {}
  var s = states || {}
  if (!(d && d.isPresent && !onBattery)) return false          // <-- no threshold check

  var fraction = batteryFraction(d)
  if (d.state === s.Discharging) return false
  if (d.state === s.PendingCharge) return true
  if (d.state === s.FullyCharged && fraction < 0.99) return true   // <-- fires here
  if (d.state !== s.Charging || fraction >= 0.99) return false

  return Number(d.changeRate || 0) <= 0.2 || Number(d.timeToFull || 0) >= 8 * 60 * 60
}
```

So the two components disagree on the same machine. The CLI is right:

```
$ omarchy battery status --shell
percentage      94%
state           fully-charged
rate            0W
size            71Wh
time
cycles          113
```

while `plugins/panels/power/Panel.qml:444-449` renders "Charge limit" / "Holding".

A secondary symptom: because the script only emits the `threshold` field when `threshold_end` is non-empty (`bin/omarchy-battery-status:114`), `batteryInfo.threshold` is undefined here, so `Panel.qml:445` falls back to `"-"`. The panel ends up showing a labelled "Charge limit" row with no value.

## Steps to reproduce

Any machine that has no `charge_control_*` sysfs attributes and whose firmware reports `fully-charged` below 99% while on AC. Apple laptops do this by design:

1. Charge to ~95%, unplug briefly, plug back in.
2. Wait for the SMC to settle into not-recharging (`current_now` reads 0, `status` reads `Full`).
3. Open the power panel.

## Suggested fix

Give `Model.chargeThresholdActive()` the same guard the shell script has — only treat the state as a held charge when a threshold is actually known. Since the script already omits the `threshold` field when there is none, `Panel.qml` could pass `batteryInfo.threshold` in and bail out when it is empty, keeping the two implementations in agreement.

## System

- Omarchy 4.0.2-1
- Kernel 7.1.9-arch1-2, Hyprland 0.56.2
- Apple MacBookPro12,1 (13" Retina Early 2015), Intel Core i5-5287U (Broadwell)
- Battery: SMP bq20z451, 71.2/74.9 Wh (95.1% health), 113 cycles

## Related

- #10121 (T2 Macs: charge limiting unreachable) asks that any future charge-limit support "degrade cleanly rather than assume `charge_control_end_threshold` exists". This is the same class of problem in an existing component: the panel already assumes it. Both machines are Apple laptops with no `charge_control_*` at all — pre-T2 here, T2 there.
- #9586 concerns the threshold *value* being wrong when one genuinely exists (UPower's fixed ThinkPad default). Distinct from this, which is a threshold being reported where none exists.

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 10:48 UTC