START-HERE: the page to open when something is broken
Doctrine explains why the system is shaped the way it is and is the wrong thing to open when the screen is black. This is for that: USB unreachability (with the ARP test that proves the phone is fine), the black-screen regression and its mechanism, what to do when a Hyprland binding stops existing, where to build, the three different ways things reach the phone and why an overlay-only fix never arrives, and the five traps that have each cost a session. Every repo's CLAUDE.md now points here before it points at doctrine.
This commit is contained in:
parent
d10479710d
commit
9e2e193af3
2 changed files with 212 additions and 0 deletions
208
START-HERE.md
Normal file
208
START-HERE.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# 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.
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
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-viewtop` — **not** `~/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:
|
||||
|
||||
```sh
|
||||
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 | hand-copied to `/usr/local/bin` | Not packaged yet — TASK-25. |
|
||||
| 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
|
||||
|
||||
```sh
|
||||
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`.
|
||||
|
||||
Away from home the phone has no wifi — the SSIDs are pinned to the home network —
|
||||
so USB is the only path, which is why §1 matters.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
Loading…
Reference in a new issue