Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/tasks/unify-shell-trees-laptop-phone.md

11 KiB

TASK: Unify the Souveraine shell trees — laptop, phone, SouveraineOS

Status: DONE — verified 2026-07-31. Every goal in this file is met. Zero stranded files; the drift it was filed against is gone; it blocks nothing. Ready to move to archive/. Filed: 2026-07-21

Re-measured 2026-07-31 (md5 of every file, both devices)

2026-07-21 (filed) 2026-07-31
files differing in content 918 7
laptop-only 30 0
phone-only 13 4 (intentional overlay)

The fix landed without this task being worked: deploy.sh now rsyncs the repo's ii-base/~/.config/quickshell/ii on both devices ("ii synced from pin"), then layers ii-phone/ on aarch64. That is option (A) from §1 below — a pinned base both devices deploy from — and it killed the independent drift. modules/settings/system/ (the whole Wifi/Bluetooth/Vpn/Monitor suite) and SettingsHome.qml are now byte-identical across repo, laptop and phone.

The 4 phone-only files are the declared overlay and are correct: AutoRotateToggle.qml, WallpaperShuffleToggle.qml, AndroidAutoRotateToggle.qml, AndroidWallpaperShuffleToggle.qml.

Stranded files remaining: ZERO

Every one of the 7 content differences is a declared, version-controlled phone override. ii-phone/ is exactly 11 files and accounts for all of them:

modules/common/models/quickToggles/AutoRotateToggle.qml
modules/common/models/quickToggles/WallpaperShuffleToggle.qml
modules/ii/bar/BarContent.qml            ← carrier + signal, far-left
modules/ii/bar/ClockWidget.qml           ← per-instance date format
modules/ii/bar/Resources.qml             ← one rotating stat (540px bar)
modules/ii/onScreenKeyboard/layouts.js
modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAutoRotateToggle.qml
modules/ii/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml
modules/ii/sidebarRight/quickToggles/androidStyle/AndroidWallpaperShuffleToggle.qml
scripts/colors/switchwall.sh             ← skip the blocking upscayl prompt
services/Audio.qml

That is §3's "declared home for phone-specific files", built and working.

§2 is done too — the KEEP list was promoted, not lost

The 07-21 record lists services/Cellular.qml, services/Souveraine.qml and modules/ii/dock/DockStack.qml as untracked phone-only files at risk. All three are now in the repo, in deploy.sh's manifest, and live on the phone — promoted to first-class overrides exactly as §2 asked. They are no longer in the ii tree because they no longer belong there.

(Beware when auditing this: those files live in the souveraine tree, not ii. Checking ~/.config/quickshell/ii/services/Cellular.qml reports them missing and is the wrong tree — that mistake was made on 2026-07-31 and briefly recorded here as data loss. They were never lost.)

One correction that does stand

deploy.sh --phone no longer "only rsyncs surfaces/quickshell/" — it rsyncs the pinned ii-base with --delete, then layers ii-phone. That --delete is precisely why an undeclared phone-local edit cannot survive a deploy, and why the overlay above is the only correct home for one. Owner rule: builds on archdev only; deploy from laptop. See souveraine-build-deploy memory + souveraine-work-rules.

The problem (one sentence)

The laptop and the phone are the same platform, but their shell code lives in two independently-maintained trees that have silently diverged by ~900 files, so fixes and features land on one device and never reach the other — and there is no source of truth that spans both.

Why this bit us today

Chasing a dock/ScreenCorners fullscreen bug, work landed in ~/.config/quickshell/ii/ on the laptop — an untracked, borrowed-upstream tree that:

  1. is not in the souveraine repo (so it's not source-controlled), and
  2. is not carried by deploy.sh --phone (only surfaces/quickshell/ rsyncs),

so the "fix" reached nothing on the phone. The phone had to be hot-patched in place. That patch now lives ONLY on the phone's disk, untracked, and the next deploy.sh recompose can revert it. This is unsustainable.

Ground truth (measured 2026-07-21)

Two trees per device under ~/.config/quickshell/:

  • souveraine/ — composed by surfaces/quickshell/deploy.sh. Our files are repo symlinks (manifest in deploy.sh); everything else is a whole-dir symlink borrowed from the sibling ii/ tree.
  • ii/ — the illogical-impulse / dots-hyprland upstream base. Maintained independently on each device. Not in any repo. Not synced by anything.

Surface tree (surfaces/quickshell/ in the souveraine repo) — GOOD

Laptop repo experimental/session-trust-phase1 vs phone rsync target (~/souveraine-surfaces/quickshell/): only 2 files differ, both this session's uncommitted edits:

  • modules/ii/dock/Dock.qml
  • modules/settings/WallpaperConfig.qml

The phone surface is not a git repo — it's a plain rsync target. No history.

ii base tree — BROKEN, this is the whole problem

Laptop ii vs phone ii (rsync dry-run, whole tree):

  • 918 files differ in content
  • 30 files exist on the laptop but NOT the phone — the phone is behind
  • 13 files exist on the phone but NOT the laptop — mix of real + junk

30 phone-missing highlights (laptop is ahead — the phone should get these):

  • scripts/colors/random/random_wallhaven_wall.sh ← the wallhaven script from earlier this session NEVER reached the phone
  • entire modules/settings/system/WifiConfig, WifiAdvancedConfig, WifiKnownConfig, BluetoothConfig, VpnConfig, MonitorConfig, KdeConfig
  • modules/settings/SettingsHome.qml
  • services/ClaudeUsage.qml, services/FileSearch.qml, services/NetworkTraffic.qml, services/PhysicalKeyboard.qml
  • modules/ii/bar/ClaudeUsageBar.qml, pomodoro widgets, background stat widgets
  • services/ai/OpenAiResponsesApiStrategy.qml

13 phone-only files — DO NOT blindly delete these:

  • KEEP (real phone-specific): services/Cellular.qml (phone has a modem, laptop doesn't), modules/common/models/quickToggles/AutoRotateToggle.qml, WallpaperShuffleToggle.qml, modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAutoRotateToggle.qml, AndroidWallpaperShuffleToggle.qml, phone-side services/Souveraine.qml, modules/ii/dock/DockStack.qml, modules/ii/sidebarLeft/SidebarLeft.qml(?)
  • JUNK (stale backups, delete): *.bak-osk-20260711-*, QuickSliders.qml.pre-audio-null-20260711, switchwall.sh.bak-upscale, services/Idle.qml.bak-20260711-130054, services/Audio.qml.bak-pipewire-20260714-123729

A naive rsync --delete laptop→phone would destroy the phone's cellular service and rotation toggles. It must be a reviewed merge, not a blind push.

The real fix (design — decide in the session)

Three intertwined decisions:

1. Bring the ii base under version control and sync it

The ii tree is the actual source of drift. Options:

  • (A) Vendor a pinned ii snapshot into a repo (SouveraineOS or a submodule) and have BOTH devices deploy from that pin — kills independent drift dead.
  • (B) Keep upstream ii as a tracked fork with a known base commit + our patch set on top, re-syncable per device.
  • Recommendation: (A). We already treat ii as a frozen base we borrow from; pin it so "borrowed" means "borrowed from the same commit everywhere."

2. Everything device-agnostic that we patch must become a repo override

ScreenCorners is the poster child: it's a fix we NEED on the phone but it lived in the borrowed base. Any file we modify must move into surfaces/quickshell/ + the deploy.sh manifest so it ships. Audit for other stranded edits in ii on both devices before pinning (diff each device's ii against the chosen upstream pin; every local delta is either a patch to promote or upstream drift to drop).

3. Make "phone follows laptop" the default, safely

  • Phone surface should become a deploy from the repo, not a bare rsync target (or at least record the deployed commit on the phone so drift is detectable).
  • Phone-specific files (Cellular, rotation/wallpaper toggles) need a declared home — a platform/phone/ overlay in the manifest — so a full sync can't clobber them. Right now they survive only because nothing syncs ii.

Concrete steps (draft — refine in session)

  1. Snapshot both devices' ii first (tar both ~/.config/quickshell/ii, laptop + phone) so nothing is lost. Store off-device.
  2. Pick the upstream ii pin (likely the laptop's current ii, it's ahead). Diff BOTH devices' ii against it; classify every delta: promote-to-override, phone-platform-overlay, or drop-as-upstream-drift.
  3. Promote all device-agnostic patches (ScreenCorners fallback, wallhaven script, anything else found) into surfaces/quickshell/ + manifest.
  4. Give phone-only files a real home in a phone overlay in the manifest.
  5. Commit the two dangling laptop edits (Dock.qml fallback, WallpaperConfig.qml folder-browsing) — they're currently uncommitted on experimental/session-trust-phase1.
  6. Rebuild the deploy so deploy.sh --phone reproduces a phone identical to the laptop's shell plus the phone overlay, from tracked sources only.
  7. Verify on the phone: fullscreen settings hides dock+corners; wallhaven button works; cellular + rotation still present; no QML errors.
  8. Decide SouveraineOS's role — is it the home for the pinned ii and the deploy tooling? (It already documents the components; it's the natural owner.)

Interim state (what's live right now, 2026-07-21)

  • Laptop repo, uncommitted: Dock.qml (fullscreen fallback), WallpaperConfig.qml (folder browsing). On experimental/session-trust-phase1.
  • Laptop ii (untracked): ScreenCorners.qml fallback patch, wallhaven script.
  • Phone, hot-patched in place (untracked, may be reverted by recompose):
    • ~/souveraine-surfaces/quickshell/modules/ii/dock/Dock.qml — fallback
    • ~/.config/quickshell/ii/modules/ii/screenCorners/ScreenCorners.qml — fallback
    • Shell restarted, qs -c souveraine active/running, no QML errors.
  • Phone is behind the laptop on ~918 ii files incl. the wallhaven script and the whole modules/settings/system/ config suite.

The fallback patch itself (for reference / re-application)

Both Dock.qml and ScreenCorners.qml detect fullscreen via ws.toplevels.values.filter(w => w.wayland?.fullscreen), which uses ext-foreign-toplevel-list and never sees standalone qs -p windows (souveraine-settings). The fix adds a fallback to Hyprland's own IPC, already polled by HyprlandData (qs.services):

// after the existing workspace-scan bool:
    || HyprlandData.activeWindow?.fullscreen === 2   // 2 = real fullscreen

HyprlandData.updateAll() re-polls on every Hyprland raw event, so it reacts when settings goes fullscreen. Requires import qs.services (both files already have it). Supersedes docs/tasks/archive/fix-dock-fullscreen-detection.md.