TASK-26: sensor evidence and a single authority over it
The device state machine is not observational, it is blind: nothing in any repo ever sends SensorInput, so observed_confidence cannot leave 0.0 and the forensic log cannot fill. Meanwhile blueline-proximity-lock is live and acting on proximity on its own authority, unowned by any package. Carved as its own task because 08(a) and 15 are both efferent and assume afferents that do not exist - wiring actuators first would manufacture exactly the success-shaped switches 19 forbids. Also: 08(b) corrected (ChargeType and PercentageTrusted existed on the bus but reported defaults for days; three fixes needed, only the third moved it), 25 gains the real kernel blockers and the unowned-file inventory, and STATE no longer claims the kernel ships by pacman.
This commit is contained in:
parent
182368014e
commit
7cb55401e6
4 changed files with 208 additions and 4 deletions
18
STATE.md
18
STATE.md
|
|
@ -28,9 +28,18 @@ regression, not a fallback.
|
|||
kernel + initramfs onto those generic names. **`boot_a` is stale** — it still
|
||||
carries `pmos_root_uuid` and no `root=`, so it is NOT what boots the system.
|
||||
Flashing it changes nothing.
|
||||
- Everything is packaged: `souveraine`, `-secrets`, `-machined`, `-sessiond`
|
||||
(aarch64 only — the laptop hits lock-screen errors with sessiond),
|
||||
`upower-souveraine`, kernel. Nothing belongs in `/usr/local/bin` any more.
|
||||
- Packaged and delivered by `pacman -Syu`: `souveraine`, `-secrets`,
|
||||
`-machined`, `-sessiond` (aarch64 only — the laptop hits lock-screen errors
|
||||
with sessiond), `upower-souveraine`. Nothing belongs in `/usr/local/bin`
|
||||
any more.
|
||||
- **The kernel is NOT yet in that list** (corrected 2026-07-25). It was
|
||||
`pacman -U`'d by hand; `kernel.yml` has never once passed and
|
||||
`kernel-latest` has never been published. Three blockers precede
|
||||
`repo-add --sign` — see TASK-25. Parked by Casey 2026-07-25.
|
||||
- **5,624 files under `/usr /etc /opt /boot` are still owned by nothing** —
|
||||
the same disease, not yet colliding. One of them,
|
||||
`blueline-proximity-lock`, is a running second authority over proximity
|
||||
(TASK-26). Inventory + the conflict-computation recipe: TASK-25.
|
||||
|
||||
**Real reasons to flash, and only these:** the boot chain itself is broken
|
||||
(pocketboot/extlinux/initramfs unbootable), partitioning changes, or a
|
||||
|
|
@ -184,5 +193,8 @@ to Gitea (`Fimeg/Chatty`, `Fimeg/libcmatrix`, `Fimeg/qtpim`).
|
|||
- `session-trust-map.html` — moved from ~/ on 2026-07-16.
|
||||
- `DUMP-pacman-pipeline-2026-07-24.md` — the session that retired flashing:
|
||||
pacman pipeline, the eleven unowned binaries, and the traps found.
|
||||
**Corrected 2026-07-25** — its charge-type conclusion was wrong (the `N/A`
|
||||
was read from the charger, not the battery); see the inline correction and
|
||||
TASK-08(b).
|
||||
- DEPRECATED: `qtpim-contacts-handoff.md`, `contacts-design.md`,
|
||||
`chatty-matrix-features.md` — historical, superseded by Matrix sensorium.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,30 @@ Wants (from handoff doc item 12):
|
|||
constant_charge_current_max 1950000 (capped at 1C = 2.97A)
|
||||
|
||||
upower exposes `ChargeType` + `PercentageTrusted` over D-Bus (the
|
||||
Souveraine fork, `souveraine/charge-type`). pop-os/system76-power
|
||||
Souveraine fork, `souveraine/charge-type`). **Both properties existed but
|
||||
reported defaults until 2026-07-25 — do not trust a D-Bus property merely
|
||||
because it is present.** `ChargeType` read `unknown` and
|
||||
`PercentageTrusted` read `no` on hardware for days. Three fixes were
|
||||
needed, and neither of the first two moved the symptom on its own:
|
||||
`628283f` (kernel spells NONE as `N/A`), `718e921` (SDM845 splits fuel
|
||||
gauge from charger — `qcom-battery` has **no** `charge_type`; walk the
|
||||
kernel's device links to `pmi8998-charger`), and `f974714` — the one that
|
||||
actually did it: `up-enumerator-udev.c` tries
|
||||
`UP_TYPE_DEVICE_SUPPLY_BATTERY` first for every power_supply and only falls
|
||||
back to `UP_TYPE_DEVICE_SUPPLY`, so a real battery never ran the refresh
|
||||
where the fork set these. `beb94dc` fixes `PercentageTrusted`, whose
|
||||
heuristic tested `charge_full` — absent here, and not what upower reads the
|
||||
percentage from anyway (it uses `capacity`).
|
||||
**Verified on device 2026-07-25: `charge-type: fast` against the charger's
|
||||
`Fast`.** Note `charge_type` (active regime) is a different attribute from
|
||||
`charge_types` (the settable profile list `up-device-supply-battery.c`
|
||||
already uses for thresholds) — easy to conflate when wiring (b).
|
||||
Hardware gaps that are not bugs: `charge_full`, `charge_now`, `energy_*`,
|
||||
`cycle_count` and model/serial are all absent, so `energy-full` falls back
|
||||
to design (13.068 Wh), health reads a meaningless 100%, and charge-cycles
|
||||
is N/A. Also seen: `temp` = 570 → **57 °C while charging** — verify whether
|
||||
that is real before building thermal policy on it.
|
||||
pop-os/system76-power
|
||||
`charge_thresholds.rs` is still the capability-probing pattern to copy —
|
||||
probe, do not assume, since the attrs exist only on this kernel.
|
||||
Cosmetic: 4.4V encodes to 4.395V so the threshold getter reads 99, not
|
||||
|
|
|
|||
|
|
@ -35,6 +35,40 @@ and have every producer publish into it.
|
|||
publish into the shared `edge` release — `souveraine/.gitea/workflows/ci.yml`
|
||||
lines ~248-256 are the reference implementation. Kernel updates then arrive
|
||||
by `pacman -Syu`; flashing becomes a recovery tool, not a release channel.
|
||||
|
||||
**`repo-add --sign` is NOT the first blocker** (verified 2026-07-25;
|
||||
parked by Casey the same day). Three things sit in front of it:
|
||||
|
||||
- **The job has never once passed.** 11 runs, 11 failures, none since
|
||||
Jul 14; `kernel-latest` is a 404 and has never been published. The Jul 14
|
||||
chain (`b1d3226` → `9c51f3f`) was successive gitea-credential fixes to
|
||||
`build.sh` and **the last fix was never re-run** — it may already work.
|
||||
- **`pkgver` is static.** `kernel/PKGBUILD:12-13` is `pkgver=7.1.1` /
|
||||
`pkgrel=1`; the commit lives only in the kernelrelease, so every build is
|
||||
`7.1.1-1` and `-Syu` can never see an upgrade. `build.sh:27-28` hardcodes
|
||||
both artifact filenames — they must become dynamic in the same change.
|
||||
- **The obvious fix is non-monotonic.** `vercmp 7.1.1.g588929024
|
||||
7.1.1.gaaa111222` → `-1`: a bare `.g<sha>` sorts as hex, so a newer
|
||||
kernel can sort *below* an older one. Use `7.1.1.r<count>.g<sha>`
|
||||
(verified monotonic), matching souveraine's own scheme. Never `+`.
|
||||
|
||||
**Archive shape — Casey chose "additive" 2026-07-25.** Publishing into the
|
||||
shared `edge` release as written above does not work today: `ci.yml`
|
||||
**deletes the release and tag and recreates it**, uploading only its own
|
||||
`pacman-repo` (which it `rm -rf`s first), so anything another producer
|
||||
published there is erased on the next souveraine push. ci.yml must stop
|
||||
delete-and-recreate; each producer then does read-modify-write on
|
||||
`souveraine-<arch>.db` under a shared archdev flock (`repo-add` replaces
|
||||
the same-pkgname entry, so old versions drop out), uploading its own
|
||||
packages plus the refreshed db and deleting only its own superseded
|
||||
assets. Both jobs are `runs-on: archdev`, so one flock serialises them.
|
||||
|
||||
Two things that make it easier than expected: the archive key
|
||||
`3CD9E99E…C8E911` is **already a secret key in casey's gpg keyring on
|
||||
archdev** and souveraine's CI signs with it there, so kernel.yml needs no
|
||||
new signing secret; and `~/.git-credentials` on archdev holds both
|
||||
`oauth2:` and `casey:` gitea entries. Pixel3Arch CI does still need a
|
||||
token that can write to `Fimeg/souveraine`.
|
||||
2. **squeekboard + stevia** are Pixel3Arch packages — once the kernel job is
|
||||
generalised into a "build these packages, sign, publish" job, they are extra
|
||||
entries in it, not new pipelines.
|
||||
|
|
@ -116,6 +150,40 @@ live sysfs + D-Bus backend, so a battery/charge page can be honest today.
|
|||
So: package the surfaces → expose what already actuates (charge, existing
|
||||
pages) → add state-machine controls as TASK-15/08 wire them up.
|
||||
|
||||
## The actual inventory (measured 2026-07-25)
|
||||
|
||||
379,153 files under `/usr /etc /opt /boot`; **5,624 owned by nothing**. The
|
||||
same disease as the eleven binaries, just not yet colliding: 16
|
||||
`/usr/bin/blueline-*` scripts, the `gadget-*` set, `clatd`, `mmsdtng`,
|
||||
`qmic`, `qrtr-*`, `rmtfs`, a hand-installed `Qt6Contacts` cmake tree,
|
||||
`libcmatrix.so.0u` (the `ldconfig` warning on every transaction), and stale
|
||||
`chatty.orig-pacman` / `chatty.pacman-orig` leftovers.
|
||||
|
||||
One of them, `blueline-proximity-lock`, is not merely unpackaged — it is a
|
||||
**running second authority** over proximity. See TASK-26.
|
||||
|
||||
**`pacman -Syu` had been blocked for days by exactly one of these files.**
|
||||
Intersecting the unowned set against the 112,051 files shipped by the 199
|
||||
pending packages gave a conflict set of ONE:
|
||||
`/usr/include/aquamarine/backend/FrameScheduler.hpp`, hand-dropped Jul 9 into
|
||||
a directory whose every other header belongs to `aquamarine 0.12.1-1`, and
|
||||
shipped by `extra/aquamarine 0.13.0-2`. It was also a version-mismatched
|
||||
header sitting in the include path the whole time. Backed up to
|
||||
`/var/backups/unowned-preupgrade/` and removed.
|
||||
|
||||
**Compute conflicts, do not guess at them:**
|
||||
|
||||
pacman -Fy
|
||||
pacman -Ql | awk '{print $2}' | sed 's#/$##' | sort -u > owned
|
||||
find /usr /etc /opt /boot -xdev \( -type f -o -type l \) | sort -u > ondisk
|
||||
comm -13 owned ondisk > unowned
|
||||
pacman -Qu | awk '{print $1}' > pending
|
||||
xargs -a pending pacman -Fl | awk '{print "/" $2}' | sed 's#/$##' | sort -u > newfiles
|
||||
comm -12 unowned newfiles # <- exactly what will abort -Syu
|
||||
|
||||
The phone's login shell is **zsh** — no `mapfile`; run this under `bash -s`
|
||||
over ssh.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Pushing to any SouveraineOS repo produces a signed package in
|
||||
|
|
|
|||
101
docs/tasks/26-sensor-evidence-single-authority.md
Normal file
101
docs/tasks/26-sensor-evidence-single-authority.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# TASK 26 — Sensor evidence, and a single authority over it
|
||||
|
||||
**Status:** open — carved 2026-07-25 after finding the device state machine
|
||||
is not "observational", it is **blind**, and that a second authority is
|
||||
already acting on the signal it was built to arbitrate.
|
||||
|
||||
**Blocks:** TASK-08(a) idle tiers, TASK-15 idle coordinator. Both are
|
||||
efferent — they give the machine actuators. Neither supplies it afferents,
|
||||
and both read as though something already does.
|
||||
|
||||
## The finding
|
||||
|
||||
`souveraine-sessiond` is running, package-owned, and answering IPC. Its
|
||||
state machine is live:
|
||||
|
||||
{"device_state":"active","display_active":true,"locked":false,
|
||||
"observed":false,"observed_confidence":0.0,"phase":"released",
|
||||
"shell_alive":true,"suppress_dpms_wake":false}
|
||||
forensic_log -> {"count":0,"entries":[]}
|
||||
|
||||
`observed_confidence` is **0.0 and structurally cannot move**, and the
|
||||
forensic buffer **cannot fill**. `src/sessiond/protocol.rs` defines
|
||||
`Request::SensorInput(SensorInput)` for proximity / accelerometer / light /
|
||||
touch, and **nothing in any repo ever sends one.** The only match for
|
||||
`SensorInput` outside sessiond itself is
|
||||
`surfaces/quickshell/services/SessionAudit.qml:logSensorInput()` — a logging
|
||||
helper with no callers. `SessiondBridge.qml` implements only the lock
|
||||
handoff (`shell_ready` / `locked_ack`), not evidence.
|
||||
|
||||
The DUMP's "still observational — it logs, it drives nothing" undersells
|
||||
this. It logs nothing either. It has no inputs.
|
||||
|
||||
## The second authority
|
||||
|
||||
Proximity evidence **does** exist on the device and is **already being acted
|
||||
on** — by a shell script:
|
||||
|
||||
pid 981 /bin/sh /usr/bin/blueline-proximity-lock
|
||||
pid 1227 monitor-sensor --proximity
|
||||
|
||||
`blueline-proximity-lock` blanks the panel when proximity is blocked while
|
||||
the lockscreen is up. It is unowned by any package (`pacman -Qo` → "No
|
||||
package owns"), one of the 5,624 unowned files in package territory
|
||||
(TASK-25). It reaches its own conclusion from proximity and acts on the
|
||||
display, with no reference to sessiond's state machine.
|
||||
|
||||
That is two authorities over one signal — the shape
|
||||
`SESSION-AUTHORITY-DOCTRINE.md` exists to forbid, and the same collision
|
||||
called out for `org.freedesktop.secrets` vs gnome-keyring on 2026-07-24.
|
||||
|
||||
## Why this must precede TASK-08(a) / TASK-15
|
||||
|
||||
TASK-19's rule is that every control is a view over the owning service — no
|
||||
success-shaped switches. A control over `observed_confidence` today would be
|
||||
a view over a constant. Wiring actuators to a machine with no afferents
|
||||
manufactures exactly the lie TASK-19 forbids: settings whose backing state
|
||||
is always the default, which will *look* correct in the UI and be inert.
|
||||
|
||||
**Sensors before actuators.** This task is the precondition, not a parallel
|
||||
track.
|
||||
|
||||
## Shape
|
||||
|
||||
1. **An evidence producer.** Something must call `SensorInput`. Proximity is
|
||||
available today via iio-sensor-proxy (`monitor-sensor --proximity`), which
|
||||
is what `blueline-proximity-lock` already consumes. Decide the owner:
|
||||
sessiond subscribing to iio-sensor-proxy over D-Bus directly is the
|
||||
straight line (it already owns lock state, and TASK-15 notes the
|
||||
coordinator likely *is* sessiond), versus the shell relaying — but the
|
||||
shell is the wrong owner for evidence that must survive shell death, which
|
||||
is the whole reason sessiond exists.
|
||||
2. **Retire the competing authority.** `blueline-proximity-lock` either
|
||||
becomes a client of the state machine or its behaviour moves into it. It
|
||||
must not keep deciding on its own. Its actual behaviour is worth
|
||||
preserving — the locked-screen proximity blank is a real feature, and
|
||||
`blueline-screen-toggle`'s DT2W proximity gate is a related second
|
||||
consumer; check that one too.
|
||||
3. **Audit the other sensors.** `accelerometer` is claimed but
|
||||
`monitor-sensor` reports *"Failed to claim accelerometer: NoReply"* —
|
||||
determine whether that is contention with the running script or genuinely
|
||||
absent. iio devices present are only `pmic@0:adc@3100` and
|
||||
`pmi8998-rradc` (PMIC analog), so accel/light provenance needs
|
||||
establishing before the protocol's four sources are assumed available.
|
||||
Do not design for evidence that does not exist.
|
||||
4. **Package whatever survives** — see TASK-25. An authority that lives in an
|
||||
unowned `/usr/bin` script cannot be reasoned about or updated.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `observed_confidence` moves off 0.0 in response to a real physical event.
|
||||
- `forensic_log` returns entries with `count > 0` after that event.
|
||||
- Exactly one component acts on proximity; `pacman -Qo` names a package for
|
||||
it.
|
||||
- The locked-screen proximity blank still works (no regression).
|
||||
|
||||
## Connects to
|
||||
|
||||
TASK-08 (device state manager — this feeds its tiers), TASK-15 (idle
|
||||
coordinator — same owner question), TASK-19 (why the ordering is not
|
||||
negotiable), TASK-25 (the script is unowned), and
|
||||
`SouveraineOS/docs/SESSION-AUTHORITY-DOCTRINE.md`.
|
||||
Loading…
Reference in a new issue