Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/START-HERE.md

9.6 KiB

START HERE

If you are picking up the phone and something is broken, this page is the whole answer. Do not go reading doctrine first.

Doctrine explains why the system is shaped the way it is and is worth reading before you design something. It is the wrong thing to open when the screen is black. This page is for that.


0. The thirty-second triage

Run this. It answers most of what a session usually spends an hour rediscovering.

Pixel3Arch/tools/phone-triage.sh

It checks, in order: can I reach the phone at all (USB, VPN, wifi), is the compositor up, is the shell up, what does the panel think it is doing, is the session class right, and is the lock/blank ordering holding. Every check prints the fix next to the failure.


1. "The phone is unreachable over USB"

It is almost certainly booted and fine. This exact symptom has cost multiple sessions.

Signature: ip neigh shows the phone REACHABLE (it answers ARP), and ICMP and ssh both time out.

Cause: a cold boot leaves two gadgets — the initramfs one and the rootfs one — so the phone ends with a dead usb0 and a live usb1, and both hold 172.16.42.1. Replies egress the dead one and vanish.

Fix, and read this part: IgnoreCarrierLoss=5s in 40-usb0.network has been correct in the repo since 2026-08-01 and was never on the device, because rootfs-overlay/ only lands on a flash and this phone updates with pacman. It is now a package:

sudo pacman -S blueline-usb-gadget      # then reboot, or:
sudo ip addr flush dev usb0             # one-shot, on the phone

Until that package is installed on a given device, expect this every cold boot.

Check which gadget you are talking to — this tells you whether the phone finished booting:

sudo dmesg | grep "SerialNumber: " | tail -3
#   dbg-initramfs   -> still in the initramfs (serial consoles on ttyACM0/1)
#   google,blueline -> the real rootfs is up

error -71 on enumeration is a cable, not the phone. device descriptor read/64, error -71 retrying forever is EPROTO — try another port, then another cable, before touching anything else.

Never warm-reboot blueline to fix a cable. A warm reboot poisons TZ/remoteproc state; recovery from that is a true cold boot. Power off fully.


2. "The screen is black after login"

Regression fixed 2026-08-02 in souveraine-viewtop 1fa1ea1. If you see it again, the mechanism is worth knowing because the shape recurs:

disclosure_locked() was authority.locked || position.hides_session(). When the protocol unlocks, position clears — but the authority half stays true until sessiond's poll catches up, and while it is true frame_elements composites lock surfaces and nothing else. The client has just destroyed those surfaces, so the scene renders empty.

The OR was harmless for months because nothing ever set LockedHint. Making viewtop report it made the half true for the first time and the latent trap fired. The pattern: a dormant OR becomes a bug the day its other side starts working.


3. "A control that worked under Hyprland does nothing"

Ask first: was it a hyprland.lua binding? If yes, it did not survive, and the fix is never to re-add a binding — it is to put the behaviour in the state machine.

Everything in overlays/hypr/hyprland.lua is a checklist of things that either have been ported or still need to be. Ported so far: power button, volume, double-tap-to-wake, DPMS. Still bound to nothing: brightness keys, media keys (playerctl), osk-switch.

The rule, from DEVICE-STATE-MACHINE.md §12: a small daemon that reads a signal and calls a tool is the eighth blind actor. Behaviour enters as a sensor_input/button/input verb and leaves as an Action from tick(), through the one executor table.


4. Where to build, and where NOT to

Build host archdev, ssh -i ~/.ssh/ani root@10.10.20.123, run cargo as casey
Never build on the phone (3.5 G RAM, daily driver) or the laptop
viewtop mirror /home/casey/souveraine-viewtopnot ~/Projects/..., that one is stale
The git tree the laptop. archdev's mirrors are not git repos.

The loop is edit on the laptop → rsync UP → build → cargo fmt on archdev → rsync DOWN. Pull down before you push up and you silently revert your own work, and a build started before the push verifies the old code while looking green. Verify your change arrived (grep -c <new symbol>) before trusting a result.

viewtop's gates — and cargo clippy --workspace does not cover the render path, which is the whole kms feature:

cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo clippy -p viewtop-compositor --features kms --all-targets -- -D warnings
cargo clippy -p viewtop-compositor --features nested --all-targets -- -D warnings
cargo test --workspace
./scripts/build-cross.sh

smithay's real signatures are on archdev at ~/.cargo/git/checkouts/smithay-312425d48e59d8c8/812bd33. Read them; the laptop has no checkout.


5. How anything reaches the phone

Three different paths, and picking the wrong one is why things silently never update.

What How it ships Gotcha
souveraine, sessiond, machined, secrets pacman, built by CI on push to primary Needs the VPN up — the repo is at 10.10.20.120:4455
Device packages (pkgs/*) pacman, from Pixel3Arch CI pkgs/** has no workflow for some paths — check
rootfs-overlay/ flash only This phone does not flash. An overlay-only fix never arrives. This is TASK-28, and it is what broke USB for months.
viewtop pacman, built by CI on push to main Packaged since TASK-25 closed. /usr/bin/viewtop is owned by souveraine-viewtop; verify with pacman -Qo /usr/bin/viewtop, whose version carries the commit. Do not hand-copy over it — that is the "silently never updates" trap this table exists for. Installing does not restart it; the running compositor keeps the old binary until the session restarts.
QML shell per-file scp Never deploy.sh --phone. Check whether the live path is a symlink into ii/ or a real override; patch every copy.

A green CI run on primary can ship nothing and look identical to one that shipped. Read the jobs, not the run status.


6. Reaching the phone

ssh -i ~/.ssh/ani casey@172.16.42.1     # USB tether
ssh -i ~/.ssh/ani casey@10.10.20.234    # home wifi, via VPN

10.10.20/24 is reachable only through the VPN, and it does not autoconnect after a reboot. If gitea resolves to a Cloudflare address, the tunnel is down. On the phone: nmcli con up wiufph. On the laptop: wiufarch.

The phone does join networks that are not home. This page used to say it could not — that away from home the SSIDs are pinned and USB is the only path. On 2026-08-02 it sat on a foreign SSID at 10.10.30.213 working perfectly while that paragraph sent the reader hunting for a cable. Pass the address:

Pixel3Arch/tools/phone-triage.sh 10.10.30.213    # or export PHONE_HOST

Find it from the router, or on the phone with ip -br a show wlan0.

A phone on a foreign network cannot reach the package repo, since that lives at 10.10.20.120:4455 behind the VPN. You do not need to bring wiufph up for that — the laptop has the tunnel and the phone is on the local subnet, so fetch on the laptop and push down: gitea release → scppacman -U. Leave the phone's tunnel alone; it is the user's switch.


7. The five traps that have each cost a session or more

  1. Grepping the design docs. They argue; the argument is the content. ls -lt docs/ and read what is newest. Sessions that grep produce confident, wrong architecture — the single most reliable failure in this project.
  2. Verifying the actuator instead of the invariant. Calling blueline-screen-toggle off proves DPMS works and nothing about the lock-then-blank ordering, because it bypasses request_blank() entirely. Trigger a blank the way the machine does, then read the trail.
  3. The forensic trail is at ~/.local/state/souveraine/forensic.jsonl, not the runtime dir. It moved. Looking in the old place shows an empty file and invites the wrong conclusion.
  4. A greetd restart silently downgrades the session to Class=greeter, and logind then refuses SetLockedHint outright — after which every blank goes out on a session nobody could confirm was locked. Fixed by a drop-in, but check loginctl show-session <seat0 session> -p Class before believing anything about locking.
  5. Two actors deciding one thing. It has happened three times: hypridle vs the idle rule, the compositor vs sessiond over the panel (a press woke the phone and put it back to sleep), and the shell vs the compositor over LockedHint. When something oscillates or fights, count the writers first.

8. Then, and only then: the design docs

Read these when you are designing, not when you are debugging.

  • SESSION-AUTHORITY-DOCTRINE.md§13 first (it inverts the default the earlier sections imply), then §4, §9, §10.
  • DEVICE-STATE-MACHINE.md — §1 (why one machine, not seven blind actors), §4 (evidence and confidence), §10 (source health), §12 (an Action, not a daemon).
  • LOCK-DPMS-LESSONS.md — §1 is the lock-then-blank invariant and every way it has been broken.
  • docs/tasks/README.md — the live work. 43 (viewtop), 50 (her hand on the glass), 51 (viewtop → daily driver), 52 (atmosphere).

STATE.md is the resume anchor and goes stale; check its date.