task-33: battery and charging belong to the device state machine
This commit is contained in:
parent
d84610b86a
commit
608a9520e0
2 changed files with 85 additions and 0 deletions
84
docs/tasks/33-battery-as-device-state.md
Normal file
84
docs/tasks/33-battery-as-device-state.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# TASK 33 — Battery and charging belong to the device state machine
|
||||
|
||||
**Status:** open, raised 2026-07-26. **Size:** one session for (1), one for
|
||||
(2); (3) is a policy decision before it is code.
|
||||
**Repos:** `~/Projects/souveraine` (`packaging/upower-souveraine`,
|
||||
`surfaces/quickshell`, `src/sessiond`).
|
||||
|
||||
## Why this exists
|
||||
|
||||
Charging has no owner. Every surface reads UPower directly and renders
|
||||
whatever it says, so the phone shows things that are true field-by-field and
|
||||
wrong as a sentence: it reaches 100%, the charger terminates, and the lock
|
||||
screen counts down from 94% with the cable still plugged in. Nothing is
|
||||
broken — that is charge-termination hysteresis, the charger resting between
|
||||
top-ups — but nothing in the stack knows enough to say so, because nothing
|
||||
owns the question.
|
||||
|
||||
Every other device signal was moved behind the state machine for exactly
|
||||
this reason (`DEVICE-STATE-MACHINE.md`): a sensor reports, the machine
|
||||
decides, one surface renders the decision. Battery is the last raw feed
|
||||
still going straight to the glass.
|
||||
|
||||
## What is already true (verified live 2026-07-26, blueline)
|
||||
|
||||
- The UPower fork already publishes `ChargeType` on the battery device by
|
||||
walking the supplier device link to `pmi8998-charger` — the fuel gauge
|
||||
(`qcom-battery`) has no `charge_type` at all. Live value reads back over
|
||||
D-Bus, `emits-change`.
|
||||
- The shell now renders it: `services/ChargeRate.qml` → "Fast charging",
|
||||
"Slow charging", plus `pluggedNotCharging` so the lock surface says
|
||||
"Charged 99%" instead of a countdown. That is the *display* fix. It is
|
||||
not the logic fix, and it is not in the state machine.
|
||||
- **`/sys/class/power_supply/pmi8998-charger/charge_control_end_threshold`
|
||||
exists, is writable, and currently reads `99`.** A charge ceiling is
|
||||
available on this hardware today with no kernel work.
|
||||
- UPower nonetheless reports `ChargeThresholdSupported: false`,
|
||||
`ChargeEndThreshold: 0`. Upstream looks for the threshold attributes on
|
||||
the *battery* device; here they live on the charger — the identical
|
||||
supplier-walk bug the fork already fixed for `charge_type`.
|
||||
|
||||
## What to build
|
||||
|
||||
1. **Threshold support in the fork, the same way charge_type was done.**
|
||||
Reuse `up_device_supply_get_supplier_charge_type_str`'s device-link walk
|
||||
for `charge_control_{start,end}_threshold`, so
|
||||
`ChargeThresholdSupported` becomes true and `ChargeEndThreshold` reads
|
||||
and writes through the standard UPower API. No new interface — the one
|
||||
upstream already defines, finally reporting the truth on this device.
|
||||
Write path needs a polkit action; the shell is the agent for it.
|
||||
|
||||
2. **Charging as evidence, not as a display feed.** `device_state` already
|
||||
carries sensor evidence and health (`§10`). Charging state belongs
|
||||
there: plugged/unplugged, charge type, whether the charger is resting or
|
||||
working, and — the part no surface can currently derive — *what the
|
||||
machine concludes*, so "Charged", "Charging slowly", and "the cable is in
|
||||
but nothing is happening and that is now unusual" are one decision made
|
||||
once rather than three surfaces guessing. `sensors_degraded` (TASK-08 f)
|
||||
is the precedent for the shape.
|
||||
|
||||
3. **A charge policy, and who is allowed to set it.** Casey's framing: the
|
||||
agent might one day decide to let the pack run to 30% first, or hold it
|
||||
at 80% overnight. The mechanism now exists (1). The decision that does
|
||||
not exist is authority: a ceiling that the device sets for battery health
|
||||
is not the same as a ceiling an agent chose, and neither is the same as
|
||||
one the user asked for out loud. `SETTINGS-AUTHORITY.md` already has the
|
||||
risk tiers and propose-vs-set split; charge policy is a natural
|
||||
step-up-gated setting under it. **Decide the tier before writing the
|
||||
verb** — a programmable ceiling that silently strands the phone at 30%
|
||||
before a trip is a worse failure than never having built it.
|
||||
|
||||
## Do not
|
||||
|
||||
- Add a fourth surface that reads UPower directly. That is the problem.
|
||||
- Ship a writable ceiling before (3) has an answer.
|
||||
- Treat "discharging while plugged in" as a fault to alarm about. It is the
|
||||
normal resting state of a full pack.
|
||||
|
||||
## Connects to
|
||||
|
||||
`DEVICE-STATE-MACHINE.md` (§10 health, the evidence model), TASK-08 (the
|
||||
state manager and its two unsurfaced findings), `SETTINGS-AUTHORITY.md`
|
||||
(risk tiers), TASK-30 (whatever verbs this exposes carry the same five
|
||||
refusal codes), `upower-charge-type-sdm845` memory (the supplier-walk fix
|
||||
this reuses).
|
||||
|
|
@ -36,6 +36,7 @@ plus open threads from the 2026-07-17 session.
|
|||
| 30 | [Agent reach: verb tables across the surfaces](30-agent-reach-verb-tables.md) | half built 07-26 | sessiond has describe + refusal codes + intent; dock/apps/shell/settings do not |
|
||||
| 31 | [The radial dial](31-radial-dial.md) | open | component before contents; entries come from the verb tables, not a list in QML |
|
||||
| 32 | [The pill and the keyboard, as owned apps](32-pill-and-osk-as-apps.md) | open | both erroneous daily; neither has an owner or a shipping story |
|
||||
| 33 | [Battery and charging belong to the device state machine](33-battery-as-device-state.md) | open | last raw feed going straight to the glass; the charge ceiling is writable today |
|
||||
| — | [Unify the shell trees](unify-shell-trees-laptop-phone.md) | open | ~900-file `ii` drift; blocks durable shell fixes reaching the phone |
|
||||
|
||||
Archived (see `archive/`): 05 crash reporter — done 2026-07-21,
|
||||
|
|
|
|||
Loading…
Reference in a new issue