souveraine-admit creates or adopts one account via systemd-sysusers, writes
the root-owned mapping health reads, and reports what NSS says afterwards
instead of what it asked for. An account belongs to one agent: handing
annie's to souvie is refused in both directions, as is adopting a uid >=1000.
Binding is by SeedID, not the UUID filename — a mismatch is identity-drift.
souveraine-session is machine-tier — one per install, like souveraine.
Agent principals stay out: sysusers is per-install, admission is per
agent and per node, and a line here would mint annie on every device the
package touches. sessiond stays a user unit until the lock handshake,
PAM path and key-eviction order are proven under the new uid.
The development recipe installed the sysusers declaration; the CI package that devices consume quietly dropped it. Ship the machine-tier souveraine account in the prebuilt package and assert the file is present before publishing.\n\nThis account belongs to machined. Souvie gets her own principal through agent admission.
ChargeEvidence was the rule violated four times in one type: a side door
past the gate, the decider probing sysfs on the clock, the driver
interpreting, and nothing leaving tick(). Its comment cited bearer —
another instance of itself.
SensorSource::Charge now enters through sensor_input like every other
source, reported by sensord on a 30s poll off /sys/class/power_supply.
conclude_charge lives on the machine as its one decision; source health,
freshness and Absent/Down come from the gate for free. The 5s clock probe
is gone, the driver type is gone, and sensord ships x86_64 too: the
laptop has a battery.
/etc/pam.d/souveraine-sessiond arrived by hand on 2026-07-16 and is owned
by no package on either device — root-owned config can only arrive by
package. Same rail as souveraine-stepup, plus a bsdtar assertion so a
future drop fails the build instead of shipping quietly. TASK-76.
SESSION-AUTHORITY-DOCTRINE §3 names /etc/pam.d/souveraine-stepup by path.
Root-owned config can only arrive by package: rootfs-overlay/ reaches a
device on flash and the phone does not flash.
auth_self, never auth_admin — step-up re-proves the user to themselves, it
does not escalate. The leading '-' on pam_fpc_polkit.so loads the fingerprint
factor only where it is installed, so one file serves phone and laptop.
Inert until a consumer calls it; no src/ path does yet.
CI already built the x86_64 daemon and then threw it away — the binary and
its user unit were copied into the package only under aarch64, so the
laptop could never receive the thing every lock, blank and button report
assumes is running.
Both now ship, and the package still neither enables nor starts the unit.
Phone-only reporters and surfaces stay aarch64.
Reports down/up edges to sessiond and decides nothing. Wire it in
hyprland.lua as a bind/bindr pair — reporting only the press leaves the
machine believing the button is held forever.
blueline-proximity-lock is 113 lines of shell implementing a subtle contract
(heartbeat inside SOURCE_DOWN_AFTER, seed from the probe banner, report both
edges) that would have been hand-copied for light and again for accel. One
binary, one contract, shipped in the package instead of the rootfs overlay.
edge is a shared archive but ci.yml deleted and recreated it each push, erasing
other producers. publish-edge.sh merges into the live db under a flock and
removes only its own superseded builds. Verifies the merge kept every foreign
entry, and reads the db back before trusting it.
Two install blockers found on the phone:
- the package shipped org.freedesktop.secrets.service, which gnome-keyring
owns. souveraine-secrets holds the bus name at runtime already.
- upower reused souveraine's 0.1.rN version, which sorts below the
hand-built 1.91.3+sha, so -Syu saw a downgrade and skipped it. Now
built from upstream version + fork sha (verified vercmp = 1).
All four repo binaries were hand-copied to the phone and owned by no
package. secrets/machined ship on both arches; sessiond stays aarch64.
secrets unit repointed /usr/local/bin -> /usr/bin.
It was hand-copied to /usr/local/bin, owned by no package, so it never
updated. Not built for x86_64 — the laptop hits lock-screen errors with
it. Verified both packages assemble correctly.
seat0-active polkit rule so power off/reboot/suspend stop returning
challenge into a session with no polkit agent on the lock surface.
Lock-surface buttons stay gated behind allowPowerFromLock (opt-in) and
requirePasswordToPower. SystemGestureRail progressive gesture + mission
control nav flag.
- packaging/upower-souveraine submodule pinned at fork head (f18b1a4,
souveraine/charge-type): ChargeType + PercentageTrusted on Device
- PKGBUILD.upower.prebuilt: prebuilt meson install tree, provides/
conflicts upower, replaces stock (IgnorePkg=upower on the phone)
- ci.yml: build the fork per-arch against the aarch64 sysroot, assert
binary arch, fold into the souveraine-{arch} pacman db
- LockSurfaceHost: charge line driven by device state, not onBattery —
no more eternal 'Charging N%' on a topped-off pack
- docs/tasks/power-indication.md force-added past the docs/ gitignore
The machine seed moves out of the user session: souveraine-machined owns
/var/lib/souveraine/seed-id as the souveraine system user and serves
pubkey/sign over /run/souveraine/machined.sock (SO_PEERCRED logged,
domain-separated signatures, group-gated socket). Seed is a precondition
- provision via 'souveraine machine init --fresh|--migrate-from', the
daemon never generates. reach/consult now resolves the machine key
through the daemon with a loud legacy fallback. Hardened system unit +
sysusers shipped in the Arch package.
Both were stranded untracked in the Pixel3Arch tree; they source from
this repo, so they live here. deploy-phone.sh ships the cross-built
binary + user unit (seed-id excluded, machine binding stays doctrine);
PKGBUILD builds from a synced local checkout, no network fetch.