Watch
1
0
Fork
You've already forked SouveraineOS
0

TASK-32: record that --phone rsyncs --delete with no snapshot

Folds in the 2026-07-29 finding instead of a new task file; TASK-32 already owns
how these surfaces ship.
This commit is contained in:
Fimeg 2026-07-29 17:55:18 -04:00
commit 39c9a022b4
3 changed files with 16 additions and 94 deletions

View file

@ -66,6 +66,22 @@ owns the fix.
- Both ship by a mechanism that survives an update, or the gap is named with
the task that owns it.
## The shipping mechanism destroys on-device edits (found 2026-07-29)
Neither surface has a package; the whole quickshell tree reaches the phone only
via `deploy.sh --phone`, which is `rsync -a --delete` from the laptop checkout
into the phone's tree with **no snapshot** (`deploy.sh:246`). The local compose
snapshots to `.ii-previous`/`.souveraine-previous` first; the phone path does
not. So an on-device edit is destroyed with no record — which is how four
pkgrels of stevia came to exist only on the phone, and why Casey is "loosing my
filesystem on my daily driver".
Root cause is the install target, not the tool: `deploy.sh` writes into `$HOME`,
so it cannot tell the user's files from its own. A pacman package cannot do that
— payload to `/usr/share`, `$HOME` keeps only overrides, and pacman refuses to
clobber unowned files (`.pacnew` for owned ones). Cheap interim fix: give the
`--phone` rsync the same `snapshot_tree` the local compose already has.
## Do not
- Patch another keyboard symptom without a reference layout in hand.

View file

@ -1,93 +0,0 @@
# TASK 49 — the shell surface is not a package, and it eats on-device edits
**Status:** open, diagnosed 2026-07-29. **Repo:** `~/Projects/souveraine`
(`surfaces/quickshell/deploy.sh`, `packaging/arch/`), `Pixel3Arch`.
Casey, 2026-07-29: *"I often enough make custom changes on that end as well — so
this bothers me. I clearly want a better way and to stop loosing my filesystem on
my daily driver device."*
This is not a papercut. The phone is the daily driver and the deploy path is
destructive by construction.
## What is actually true today
`souveraine`'s CI packages the Rust binaries (`souveraine`, `souveraine-secrets`,
`souveraine-machined`, `souveraine-sessiond`) and the UPower fork, and CLAUDE.md
states the rule plainly: *"Everything this repo produces ships as a package... If
a binary needs to reach a device, it goes through the package."*
**The quickshell surface is the exception, and nothing says so.** Every mention of
quickshell under `packaging/` is an incidental comment. There is no
`souveraine-shell` package. The entire shell — every QML file, the ii base pin,
the phone overlay — reaches the phone only via `deploy.sh --phone`.
## The two exposures, precisely
| Path | Operation | Snapshot? |
|---|---|---|
| `$PHONE_DEST` (phone's copy of the surface source) | `deploy.sh:246` `rsync -a --delete` from the laptop checkout | **none** |
| `$II`, `$SV` (composed dirs under `~/.config/quickshell`) | `deploy.sh:388,391` `rsync -a --delete-delay` | yes — `.ii-previous` / `.souveraine-previous`, one generation |
So the composed trees are recoverable one deep. **The phone's source tree is
not.** `--delete` with no snapshot means an on-device edit or a new file in that
directory is destroyed with no record it existed. That is the mechanism behind
"losing my filesystem", and it is the `--phone` path specifically — the local
compose is comparatively careful.
`deploy.sh` is *not* careless otherwise: it stages into `.ii-next.$$` /
`.souveraine-next.$$`, uses `--delay-updates`, refuses to clear an unexpected
rollback path, and traps for cleanup. The problem is not hygiene. It is the
target.
## The root cause is the install target, not the tool
`deploy.sh` installs **into `$HOME`**. That is why it cannot distinguish the
user's files from its own: everything lives in one tree that one rsync owns.
No amount of flag-tuning fixes that, because the tool has no ownership model.
A pacman package cannot install into `$HOME`, and that constraint is the fix:
- **Payload to `/usr/share/souveraine/quickshell/`** — package-owned, read-only,
replaced wholesale on upgrade with no ambiguity about who owns what.
- **`$HOME` holds only overrides.** An upgrade physically cannot touch a file the
package does not own, because it never writes there.
- **pacman refuses to clobber unowned files** rather than deleting them, and
emits `.pacnew` for package-owned files the user modified — the edit survives
*and* the new version arrives beside it.
- **`pacman -Qkk souveraine-shell`** answers "what did I change?", which nothing
can answer today.
- **`backup=()`** in the PKGBUILD marks the genuinely user-editable files
explicitly, making the contract legible instead of conventional.
This also lands the surface on the `souveraine-updater` path the rest of the
system already uses, which is what Casey asked for — but note the upgradeability
is the *secondary* benefit. The primary one is that clobbering becomes
structurally impossible.
## What this needs
1. **A resolution order in the shell.** `$HOME` override → package payload →
ii pin. `deploy.sh`'s manifest already encodes exactly this three-way
composition (override / borrow-whole-dir / compose-file-by-file), so the logic
exists and moves rather than gets invented.
2. **`souveraine-shell` PKGBUILD** carrying `surfaces/quickshell/` (including
`ii-base/` at its pin and the `ii-phone/` overlay, arch-gated as
`deploy.sh` already gates on `TARGET_ARCH`).
3. **A CI job**, matching the existing binaries' shape, publishing to the
`souveraine-{arch}` db on `edge`. Note the CLAUDE.md trap: only `public`
publishes, and a skipped job does not make a run red — check the jobs, not
the run.
4. **Keep `deploy.sh` for the laptop dev loop**, where fast iteration matters and
the tree is not a daily driver. It should stop being the phone's path.
5. **Interim mitigation, cheap and worth doing first:** give the `--phone` rsync
the same `snapshot_tree` treatment the local compose already has, so a
mistaken deploy is recoverable while the package work happens.
## Connects to
- [[29-souveraine-updater]] — the pipeline this rides.
- `souveraine/CLAUDE.md` — the "everything ships as a package" rule this is the
standing exception to.
- TASK-18 (selection menu) surfaced it: new shell files currently have no route
to the phone other than the destructive one.

View file

@ -58,7 +58,6 @@ Four that are cheap relative to what they unblock:
| # | Task | What's left |
|---|------|-------------|
| 49 | [The shell surface is not a package, and it eats on-device edits](49-shell-surface-is-not-a-package.md) | `deploy.sh --phone` rsyncs `--delete` into the phone's tree with **no snapshot** — on-device edits are destroyed with no record. Root cause is installing into `$HOME`, which has no ownership model. Payload belongs in `/usr/share`, `$HOME` keeps only overrides. |
| 48 | [Shell dies on any reload that owes a lock](48-lock-surface-reload-fatal.md) | Fully diagnosed 07-29, 11 crashes since 07-17. A reload re-requests ext-session-lock while the outgoing instance still holds it → `FATAL: Tried to show lockscreen surfaces without active lock`. **Sync with TASK-43 before touching the lock path.** |
| 47 | [Auto-brightness: anchors, none of it built](47-auto-brightness-anchors.md) | §12 reads as settled and has **zero** code behind its actuation half — no brightness `Action`, no anchors, `grep anchor src/` is empty. The evidence half (lux in, health tracked) is live. |
| 46 | [Camera: **the front camera works**](46-camera-imx363.md) | **First frame captured 2026-07-29** on the running kernel — no reboot, no DT change. Both front IMX355 were already bound; nobody had tried streaming. Recipe + the stride/packing gotchas are in the task. Next: exposure controls, then libcamera. Rear IMX363 DT (`c7784b716`) still unbuilt but no longer the blocker. |